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.
51 #include <fs/nfs/nfsport.h>
52 #include <sys/extattr.h>
53 #include <sys/filio.h>
56 extern u_int32_t newnfs_false, newnfs_true;
57 extern enum vtype nv34tov_type[8];
58 extern struct timeval nfsboottime;
59 extern int nfs_rootfhset;
60 extern int nfsrv_enable_crossmntpt;
61 extern int nfsrv_statehashsize;
62 extern int nfsrv_layouthashsize;
63 extern time_t nfsdev_time;
64 extern volatile int nfsrv_devidcnt;
65 extern int nfsd_debuglevel;
66 extern u_long sb_max_adj;
67 extern int nfsrv_pnfsatime;
68 extern int nfsrv_maxpnfsmirror;
69 extern int nfs_maxcopyrange;
71 static int nfs_async = 0;
72 SYSCTL_DECL(_vfs_nfsd);
73 SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0,
74 "Tell client that writes were synced even though they were not");
75 extern int nfsrv_doflexfile;
76 SYSCTL_INT(_vfs_nfsd, OID_AUTO, default_flexfile, CTLFLAG_RW,
77 &nfsrv_doflexfile, 0, "Make Flex File Layout the default for pNFS");
78 static int nfsrv_linux42server = 1;
79 SYSCTL_INT(_vfs_nfsd, OID_AUTO, linux42server, CTLFLAG_RW,
80 &nfsrv_linux42server, 0,
81 "Enable Linux style NFSv4.2 server (non-RFC compliant)");
82 static bool nfsrv_openaccess = true;
83 SYSCTL_BOOL(_vfs_nfsd, OID_AUTO, v4openaccess, CTLFLAG_RW,
85 "Enable Linux style NFSv4 Open access check");
88 * This list defines the GSS mechanisms supported.
89 * (Don't ask me how you get these strings from the RFC stuff like
90 * iso(1), org(3)... but someone did it, so I don't need to know.)
92 static struct nfsgss_mechlist nfsgss_mechlist[] = {
93 { 9, "\052\206\110\206\367\022\001\002\002", 11 },
98 static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
99 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
100 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
101 int *diraft_retp, nfsattrbit_t *attrbitp,
102 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
104 static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
105 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
106 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
107 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
108 NFSPROC_T *p, struct nfsexstuff *exp);
111 * nfs access service (not a part of NFS V2)
114 nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram,
115 vnode_t vp, struct nfsexstuff *exp)
118 int getret, error = 0;
120 u_int32_t testmode, nfsmode, supported = 0;
122 struct thread *p = curthread;
124 if (nd->nd_repstat) {
125 nfsrv_postopattr(nd, 1, &nva);
128 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
129 nfsmode = fxdr_unsigned(u_int32_t, *tl);
130 if ((nd->nd_flag & ND_NFSV4) &&
131 (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP |
132 NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE |
133 NFSACCESS_EXECUTE | NFSACCESS_XAREAD | NFSACCESS_XAWRITE |
134 NFSACCESS_XALIST))) {
135 nd->nd_repstat = NFSERR_INVAL;
139 if (nfsmode & NFSACCESS_READ) {
140 supported |= NFSACCESS_READ;
141 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
142 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
143 nfsmode &= ~NFSACCESS_READ;
145 if (nfsmode & NFSACCESS_MODIFY) {
146 supported |= NFSACCESS_MODIFY;
147 if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
148 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
149 nfsmode &= ~NFSACCESS_MODIFY;
151 if (nfsmode & NFSACCESS_EXTEND) {
152 supported |= NFSACCESS_EXTEND;
153 if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p,
154 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
155 nfsmode &= ~NFSACCESS_EXTEND;
157 if (nfsmode & NFSACCESS_XAREAD) {
158 supported |= NFSACCESS_XAREAD;
159 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
160 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
161 nfsmode &= ~NFSACCESS_XAREAD;
163 if (nfsmode & NFSACCESS_XAWRITE) {
164 supported |= NFSACCESS_XAWRITE;
165 if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
166 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
167 nfsmode &= ~NFSACCESS_XAWRITE;
169 if (nfsmode & NFSACCESS_XALIST) {
170 supported |= NFSACCESS_XALIST;
171 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
172 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
173 nfsmode &= ~NFSACCESS_XALIST;
175 if (nfsmode & NFSACCESS_DELETE) {
176 supported |= NFSACCESS_DELETE;
177 if (vp->v_type == VDIR)
178 deletebit = VDELETE_CHILD;
181 if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p,
182 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
183 nfsmode &= ~NFSACCESS_DELETE;
185 if (vnode_vtype(vp) == VDIR)
186 testmode = NFSACCESS_LOOKUP;
188 testmode = NFSACCESS_EXECUTE;
189 if (nfsmode & testmode) {
190 supported |= (nfsmode & testmode);
191 if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p,
192 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
193 nfsmode &= ~testmode;
195 nfsmode &= supported;
196 if (nd->nd_flag & ND_NFSV3) {
197 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
198 nfsrv_postopattr(nd, getret, &nva);
201 if (nd->nd_flag & ND_NFSV4) {
202 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
203 *tl++ = txdr_unsigned(supported);
205 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
206 *tl = txdr_unsigned(nfsmode);
213 NFSEXITCODE2(error, nd);
218 * nfs getattr service
221 nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
222 vnode_t vp, __unused struct nfsexstuff *exp)
226 int at_root = 0, error = 0, supports_nfsv4acls;
227 struct nfsreferral *refp;
228 nfsattrbit_t attrbits, tmpbits;
230 struct vnode *tvp = NULL;
232 uint64_t mounted_on_fileno = 0;
234 struct thread *p = curthread;
238 if (nd->nd_flag & ND_NFSV4) {
239 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
246 * Check for a referral.
248 refp = nfsv4root_getreferral(vp, NULL, 0);
250 (void) nfsrv_putreferralattr(nd, &attrbits, refp, 1,
255 if (nd->nd_repstat == 0) {
257 NFSSET_ATTRBIT(&tmpbits, &attrbits);
260 * GETATTR with write-only attr time_access_set and time_modify_set
261 * should return NFS4ERR_INVAL.
263 if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEACCESSSET) ||
264 NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEMODIFYSET)){
265 error = NFSERR_INVAL;
269 if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) {
270 NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL);
271 accmode |= VREAD_ACL;
273 if (NFSNONZERO_ATTRBIT(&tmpbits))
274 accmode |= VREAD_ATTRIBUTES;
276 nd->nd_repstat = nfsvno_accchk(vp, accmode,
277 nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
278 NFSACCCHK_VPISLOCKED, NULL);
282 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
283 if (!nd->nd_repstat) {
284 if (nd->nd_flag & ND_NFSV4) {
285 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE))
286 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
288 nd->nd_repstat = nfsrv_checkgetattr(nd, vp,
290 if (nd->nd_repstat == 0) {
291 supports_nfsv4acls = nfs_supportsnfsv4acls(vp);
293 if (nfsrv_enable_crossmntpt != 0 &&
294 vp->v_type == VDIR &&
295 (vp->v_vflag & VV_ROOT) != 0 &&
297 tvp = mp->mnt_vnodecovered;
305 if ((nd->nd_repstat =
306 NFSVOPLOCK(tvp, LK_SHARED)) == 0) {
307 nd->nd_repstat = VOP_GETATTR(
308 tvp, &va, nd->nd_cred);
312 if (nd->nd_repstat == 0)
313 mounted_on_fileno = (uint64_t)
318 if (nd->nd_repstat == 0)
319 nd->nd_repstat = vfs_busy(mp, 0);
321 if (nd->nd_repstat == 0) {
322 (void)nfsvno_fillattr(nd, mp, vp, &nva,
323 &fh, 0, &attrbits, nd->nd_cred, p,
324 isdgram, 1, supports_nfsv4acls,
325 at_root, mounted_on_fileno);
332 nfsrv_fillattr(nd, &nva);
340 NFSEXITCODE2(error, nd);
345 * nfs setattr service
348 nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
349 vnode_t vp, struct nfsexstuff *exp)
351 struct nfsvattr nva, nva2;
353 int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
355 struct timespec guard = { 0, 0 };
356 nfsattrbit_t attrbits, retbits;
357 nfsv4stateid_t stateid;
358 NFSACL_T *aclp = NULL;
359 struct thread *p = curthread;
361 if (nd->nd_repstat) {
362 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
365 #ifdef NFS4_ACL_EXTATTR_NAME
366 aclp = acl_alloc(M_WAITOK);
370 NFSVNO_ATTRINIT(&nva);
371 if (nd->nd_flag & ND_NFSV4) {
372 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
373 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
374 stateid.other[0] = *tl++;
375 stateid.other[1] = *tl++;
376 stateid.other[2] = *tl;
377 if (stateid.other[0] == 0x55555555 &&
378 stateid.other[1] == 0x55555555 &&
379 stateid.other[2] == 0x55555555 &&
380 stateid.seqid == 0xffffffff)
383 error = nfsrv_sattr(nd, vp, &nva, &attrbits, aclp, p);
387 /* For NFSv4, only va_uid is used from nva2. */
388 NFSZERO_ATTRBIT(&retbits);
389 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
390 preat_ret = nfsvno_getattr(vp, &nva2, nd, p, 1, &retbits);
392 nd->nd_repstat = preat_ret;
394 NFSZERO_ATTRBIT(&retbits);
395 if (nd->nd_flag & ND_NFSV3) {
396 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
397 gcheck = fxdr_unsigned(int, *tl);
399 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
400 fxdr_nfsv3time(tl, &guard);
402 if (!nd->nd_repstat && gcheck &&
403 (nva2.na_ctime.tv_sec != guard.tv_sec ||
404 nva2.na_ctime.tv_nsec != guard.tv_nsec))
405 nd->nd_repstat = NFSERR_NOT_SYNC;
406 if (nd->nd_repstat) {
408 #ifdef NFS4_ACL_EXTATTR_NAME
411 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
414 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
415 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
418 * Now that we have all the fields, lets do it.
419 * If the size is being changed write access is required, otherwise
420 * just check for a read only file system.
422 if (!nd->nd_repstat) {
423 if (NFSVNO_NOTSETSIZE(&nva)) {
424 if (NFSVNO_EXRDONLY(exp) ||
425 (vfs_flags(vp->v_mount) & MNT_RDONLY))
426 nd->nd_repstat = EROFS;
428 if (vnode_vtype(vp) != VREG)
429 nd->nd_repstat = EINVAL;
430 else if (nva2.na_uid != nd->nd_cred->cr_uid ||
431 NFSVNO_EXSTRICTACCESS(exp))
432 nd->nd_repstat = nfsvno_accchk(vp,
433 VWRITE, nd->nd_cred, exp, p,
434 NFSACCCHK_NOOVERRIDE,
435 NFSACCCHK_VPISLOCKED, NULL);
439 * Proxy operations from the MDS are allowed via the all 0s special
442 if (nd->nd_repstat == 0 && (nd->nd_flag & ND_NFSV4) != 0 &&
443 gotproxystateid == 0)
444 nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid,
445 &nva, &attrbits, exp, p);
447 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
449 * For V4, try setting the attrbutes in sets, so that the
450 * reply bitmap will be correct for an error case.
452 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) ||
453 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) {
454 NFSVNO_ATTRINIT(&nva2);
455 NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid);
456 NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid);
457 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
459 if (!nd->nd_repstat) {
460 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER))
461 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
462 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP))
463 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP);
466 if (!nd->nd_repstat &&
467 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) {
468 NFSVNO_ATTRINIT(&nva2);
469 NFSVNO_SETATTRVAL(&nva2, size, nva.na_size);
470 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
473 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE);
475 if (!nd->nd_repstat &&
476 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) ||
477 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) {
478 NFSVNO_ATTRINIT(&nva2);
479 NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime);
480 NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime);
481 if (nva.na_vaflags & VA_UTIMES_NULL) {
482 nva2.na_vaflags |= VA_UTIMES_NULL;
483 NFSVNO_SETACTIVE(&nva2, vaflags);
485 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
487 if (!nd->nd_repstat) {
488 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET))
489 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET);
490 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))
491 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET);
494 if (!nd->nd_repstat &&
495 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE) ||
496 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED))) {
497 NFSVNO_ATTRINIT(&nva2);
498 NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode);
499 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
501 if (!nd->nd_repstat) {
502 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE))
503 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
504 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED))
505 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODESETMASKED);
509 #ifdef NFS4_ACL_EXTATTR_NAME
510 if (!nd->nd_repstat && aclp->acl_cnt > 0 &&
511 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) {
512 nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
514 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL);
517 } else if (!nd->nd_repstat) {
518 nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p,
521 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) {
522 postat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
524 nd->nd_repstat = postat_ret;
527 #ifdef NFS4_ACL_EXTATTR_NAME
530 if (nd->nd_flag & ND_NFSV3)
531 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
532 else if (nd->nd_flag & ND_NFSV4)
533 (void) nfsrv_putattrbit(nd, &retbits);
534 else if (!nd->nd_repstat)
535 nfsrv_fillattr(nd, &nva);
542 #ifdef NFS4_ACL_EXTATTR_NAME
545 if (nd->nd_flag & ND_NFSV4) {
547 * For all nd_repstat, the V4 reply includes a bitmap,
548 * even NFSERR_BADXDR, which is what this will end up
551 (void) nfsrv_putattrbit(nd, &retbits);
553 NFSEXITCODE2(error, nd);
559 * (Also performs lookup parent for v4)
562 nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
563 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
565 struct nameidata named;
566 vnode_t vp, dirp = NULL;
567 int error = 0, dattr_ret = 1;
568 struct nfsvattr nva, dattr;
571 struct thread *p = curthread;
573 if (nd->nd_repstat) {
574 nfsrv_postopattr(nd, dattr_ret, &dattr);
579 * For some reason, if dp is a symlink, the error
580 * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR.
582 if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) {
583 nd->nd_repstat = NFSERR_SYMLINK;
588 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
589 LOCKLEAF | SAVESTART);
590 nfsvno_setpathbuf(&named, &bufp, &hashp);
591 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
594 nfsvno_relpathbuf(&named);
597 if (!nd->nd_repstat) {
598 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
601 nfsvno_relpathbuf(&named);
603 if (nd->nd_repstat) {
605 if (nd->nd_flag & ND_NFSV3)
606 dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p,
610 if (nd->nd_flag & ND_NFSV3)
611 nfsrv_postopattr(nd, dattr_ret, &dattr);
614 if (named.ni_startdir)
615 vrele(named.ni_startdir);
616 nfsvno_relpathbuf(&named);
618 if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) &&
619 vp->v_type != VDIR && vp->v_type != VLNK)
621 * Only allow lookup of VDIR and VLNK for traversal of
622 * non-exported volumes during NFSv4 mounting.
624 nd->nd_repstat = ENOENT;
625 if (nd->nd_repstat == 0)
626 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
627 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
628 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
629 if (vpp != NULL && nd->nd_repstat == 0)
634 if (nd->nd_flag & ND_NFSV3)
635 dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p, 0,
639 if (nd->nd_repstat) {
640 if (nd->nd_flag & ND_NFSV3)
641 nfsrv_postopattr(nd, dattr_ret, &dattr);
644 if (nd->nd_flag & ND_NFSV2) {
645 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
646 nfsrv_fillattr(nd, &nva);
647 } else if (nd->nd_flag & ND_NFSV3) {
648 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
649 nfsrv_postopattr(nd, 0, &nva);
650 nfsrv_postopattr(nd, dattr_ret, &dattr);
654 NFSEXITCODE2(error, nd);
659 * nfs readlink service
662 nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
663 vnode_t vp, __unused struct nfsexstuff *exp)
666 struct mbuf *mp = NULL, *mpend = NULL;
669 struct thread *p = curthread;
671 if (nd->nd_repstat) {
672 nfsrv_postopattr(nd, getret, &nva);
675 if (vnode_vtype(vp) != VLNK) {
676 if (nd->nd_flag & ND_NFSV2)
677 nd->nd_repstat = ENXIO;
679 nd->nd_repstat = EINVAL;
682 nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p,
684 if (nd->nd_flag & ND_NFSV3)
685 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
687 if (nd->nd_flag & ND_NFSV3)
688 nfsrv_postopattr(nd, getret, &nva);
691 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
692 *tl = txdr_unsigned(len);
694 nd->nd_mb->m_next = mp;
696 nd->nd_bpos = mtod(mpend, caddr_t) + mpend->m_len;
708 nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
709 vnode_t vp, struct nfsexstuff *exp)
712 int error = 0, cnt, getret = 1, gotproxystateid, reqlen, eof = 0;
713 struct mbuf *m2, *m3;
716 struct nfsstate st, *stp = &st;
717 struct nfslock lo, *lop = &lo;
718 nfsv4stateid_t stateid;
720 struct thread *p = curthread;
722 if (nd->nd_repstat) {
723 nfsrv_postopattr(nd, getret, &nva);
726 if (nd->nd_flag & ND_NFSV2) {
727 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
728 off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
729 reqlen = fxdr_unsigned(int, *tl);
730 } else if (nd->nd_flag & ND_NFSV3) {
731 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
732 off = fxdr_hyper(tl);
734 reqlen = fxdr_unsigned(int, *tl);
736 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
737 reqlen = fxdr_unsigned(int, *(tl + 6));
739 if (reqlen > NFS_SRVMAXDATA(nd)) {
740 reqlen = NFS_SRVMAXDATA(nd);
741 } else if (reqlen < 0) {
746 if (nd->nd_flag & ND_NFSV4) {
747 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
748 lop->lo_flags = NFSLCK_READ;
749 stp->ls_ownerlen = 0;
751 stp->ls_uid = nd->nd_cred->cr_uid;
752 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
753 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
754 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
755 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
756 if ((nd->nd_flag & ND_NFSV41) != 0)
757 clientid.qval = nd->nd_clientid.qval;
758 else if (nd->nd_clientid.qval != clientid.qval)
759 printf("EEK1 multiple clids\n");
761 if ((nd->nd_flag & ND_NFSV41) != 0)
762 printf("EEK! no clientid from session\n");
763 nd->nd_flag |= ND_IMPLIEDCLID;
764 nd->nd_clientid.qval = clientid.qval;
766 stp->ls_stateid.other[2] = *tl++;
768 * Don't allow the client to use a special stateid for a DS op.
770 if ((nd->nd_flag & ND_DSSERVER) != 0 &&
771 ((stp->ls_stateid.other[0] == 0x0 &&
772 stp->ls_stateid.other[1] == 0x0 &&
773 stp->ls_stateid.other[2] == 0x0) ||
774 (stp->ls_stateid.other[0] == 0xffffffff &&
775 stp->ls_stateid.other[1] == 0xffffffff &&
776 stp->ls_stateid.other[2] == 0xffffffff) ||
777 stp->ls_stateid.seqid != 0))
778 nd->nd_repstat = NFSERR_BADSTATEID;
779 /* However, allow the proxy stateid. */
780 if (stp->ls_stateid.seqid == 0xffffffff &&
781 stp->ls_stateid.other[0] == 0x55555555 &&
782 stp->ls_stateid.other[1] == 0x55555555 &&
783 stp->ls_stateid.other[2] == 0x55555555)
785 off = fxdr_hyper(tl);
788 lop->lo_end = off + reqlen;
790 * Paranoia, just in case it wraps around.
792 if (lop->lo_end < off)
793 lop->lo_end = NFS64BITSSET;
795 if (vnode_vtype(vp) != VREG) {
796 if (nd->nd_flag & ND_NFSV3)
797 nd->nd_repstat = EINVAL;
799 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
802 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
804 nd->nd_repstat = getret;
805 if (!nd->nd_repstat &&
806 (nva.na_uid != nd->nd_cred->cr_uid ||
807 NFSVNO_EXSTRICTACCESS(exp))) {
808 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
810 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
812 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
813 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
814 NFSACCCHK_VPISLOCKED, NULL);
817 * DS reads are marked by ND_DSSERVER or use the proxy special
820 if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) ==
821 ND_NFSV4 && gotproxystateid == 0)
822 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
823 &stateid, exp, nd, p);
824 if (nd->nd_repstat) {
826 if (nd->nd_flag & ND_NFSV3)
827 nfsrv_postopattr(nd, getret, &nva);
830 if (off >= nva.na_size) {
833 } else if (reqlen == 0)
835 else if ((off + reqlen) >= nva.na_size) {
836 cnt = nva.na_size - off;
842 nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p,
844 if (!(nd->nd_flag & ND_NFSV4)) {
845 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
847 nd->nd_repstat = getret;
849 if (nd->nd_repstat) {
853 if (nd->nd_flag & ND_NFSV3)
854 nfsrv_postopattr(nd, getret, &nva);
859 if (nd->nd_flag & ND_NFSV2) {
860 nfsrv_fillattr(nd, &nva);
861 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
863 if (nd->nd_flag & ND_NFSV3) {
864 nfsrv_postopattr(nd, getret, &nva);
865 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
866 *tl++ = txdr_unsigned(cnt);
868 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
872 *tl++ = newnfs_false;
874 *tl = txdr_unsigned(cnt);
876 nd->nd_mb->m_next = m3;
878 nd->nd_bpos = mtod(m2, caddr_t) + m2->m_len;
886 NFSEXITCODE2(error, nd);
894 nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
895 vnode_t vp, struct nfsexstuff *exp)
898 struct nfsvattr nva, forat;
899 int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
900 int gotproxystateid, stable = NFSWRITE_FILESYNC;
902 struct nfsstate st, *stp = &st;
903 struct nfslock lo, *lop = &lo;
904 nfsv4stateid_t stateid;
906 nfsattrbit_t attrbits;
907 struct thread *p = curthread;
909 if (nd->nd_repstat) {
910 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
914 if (nd->nd_flag & ND_NFSV2) {
915 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
916 off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
918 retlen = len = fxdr_unsigned(int32_t, *tl);
919 } else if (nd->nd_flag & ND_NFSV3) {
920 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
921 off = fxdr_hyper(tl);
923 stable = fxdr_unsigned(int, *tl++);
924 retlen = len = fxdr_unsigned(int32_t, *tl);
926 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
927 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
928 lop->lo_flags = NFSLCK_WRITE;
929 stp->ls_ownerlen = 0;
931 stp->ls_uid = nd->nd_cred->cr_uid;
932 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
933 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
934 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
935 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
936 if ((nd->nd_flag & ND_NFSV41) != 0)
937 clientid.qval = nd->nd_clientid.qval;
938 else if (nd->nd_clientid.qval != clientid.qval)
939 printf("EEK2 multiple clids\n");
941 if ((nd->nd_flag & ND_NFSV41) != 0)
942 printf("EEK! no clientid from session\n");
943 nd->nd_flag |= ND_IMPLIEDCLID;
944 nd->nd_clientid.qval = clientid.qval;
946 stp->ls_stateid.other[2] = *tl++;
948 * Don't allow the client to use a special stateid for a DS op.
950 if ((nd->nd_flag & ND_DSSERVER) != 0 &&
951 ((stp->ls_stateid.other[0] == 0x0 &&
952 stp->ls_stateid.other[1] == 0x0 &&
953 stp->ls_stateid.other[2] == 0x0) ||
954 (stp->ls_stateid.other[0] == 0xffffffff &&
955 stp->ls_stateid.other[1] == 0xffffffff &&
956 stp->ls_stateid.other[2] == 0xffffffff) ||
957 stp->ls_stateid.seqid != 0))
958 nd->nd_repstat = NFSERR_BADSTATEID;
959 /* However, allow the proxy stateid. */
960 if (stp->ls_stateid.seqid == 0xffffffff &&
961 stp->ls_stateid.other[0] == 0x55555555 &&
962 stp->ls_stateid.other[1] == 0x55555555 &&
963 stp->ls_stateid.other[2] == 0x55555555)
965 off = fxdr_hyper(tl);
968 stable = fxdr_unsigned(int, *tl++);
969 retlen = len = fxdr_unsigned(int32_t, *tl);
970 lop->lo_end = off + len;
972 * Paranoia, just in case it wraps around, which shouldn't
973 * ever happen anyhow.
975 if (lop->lo_end < lop->lo_first)
976 lop->lo_end = NFS64BITSSET;
979 if (retlen > NFS_SRVMAXIO || retlen < 0)
980 nd->nd_repstat = EIO;
981 if (vnode_vtype(vp) != VREG && !nd->nd_repstat) {
982 if (nd->nd_flag & ND_NFSV3)
983 nd->nd_repstat = EINVAL;
985 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
988 NFSZERO_ATTRBIT(&attrbits);
989 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
990 forat_ret = nfsvno_getattr(vp, &forat, nd, p, 1, &attrbits);
992 nd->nd_repstat = forat_ret;
993 if (!nd->nd_repstat &&
994 (forat.na_uid != nd->nd_cred->cr_uid ||
995 NFSVNO_EXSTRICTACCESS(exp)))
996 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
998 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
1000 * DS reads are marked by ND_DSSERVER or use the proxy special
1003 if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) ==
1004 ND_NFSV4 && gotproxystateid == 0)
1005 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
1006 &stateid, exp, nd, p);
1007 if (nd->nd_repstat) {
1009 if (nd->nd_flag & ND_NFSV3)
1010 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
1015 * For NFS Version 2, it is not obvious what a write of zero length
1016 * should do, but I might as well be consistent with Version 3,
1017 * which is to return ok so long as there are no permission problems.
1020 nd->nd_repstat = nfsvno_write(vp, off, retlen, &stable,
1021 nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
1022 error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
1026 if (nd->nd_flag & ND_NFSV4)
1029 aftat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
1031 if (!nd->nd_repstat)
1032 nd->nd_repstat = aftat_ret;
1033 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1034 if (nd->nd_flag & ND_NFSV3)
1035 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
1038 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1039 *tl++ = txdr_unsigned(retlen);
1041 * If nfs_async is set, then pretend the write was FILESYNC.
1042 * Warning: Doing this violates RFC1813 and runs a risk
1043 * of data written by a client being lost when the server
1046 if (stable == NFSWRITE_UNSTABLE && nfs_async == 0)
1047 *tl++ = txdr_unsigned(stable);
1049 *tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
1051 * Actually, there is no need to txdr these fields,
1052 * but it may make the values more human readable,
1053 * for debugging purposes.
1055 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
1056 *tl = txdr_unsigned(nfsboottime.tv_usec);
1057 } else if (!nd->nd_repstat)
1058 nfsrv_fillattr(nd, &nva);
1061 NFSEXITCODE2(0, nd);
1065 NFSEXITCODE2(error, nd);
1070 * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
1071 * now does a truncate to 0 length via. setattr if it already exists
1072 * The core creation routine has been extracted out into nfsrv_creatsub(),
1073 * so it can also be used by nfsrv_open() for V4.
1076 nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
1077 vnode_t dp, struct nfsexstuff *exp)
1079 struct nfsvattr nva, dirfor, diraft;
1080 struct nfsv2_sattr *sp;
1081 struct nameidata named;
1083 int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
1084 int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
1086 vnode_t vp = NULL, dirp = NULL;
1091 int32_t cverf[2], tverf[2] = { 0, 0 };
1092 struct thread *p = curthread;
1094 if (nd->nd_repstat) {
1095 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1098 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1099 LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
1100 nfsvno_setpathbuf(&named, &bufp, &hashp);
1101 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1104 if (!nd->nd_repstat) {
1105 NFSVNO_ATTRINIT(&nva);
1106 if (nd->nd_flag & ND_NFSV2) {
1107 NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1108 vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
1111 NFSVNO_SETATTRVAL(&nva, type, vtyp);
1112 NFSVNO_SETATTRVAL(&nva, mode,
1113 nfstov_mode(sp->sa_mode));
1114 switch (nva.na_type) {
1116 tsize = fxdr_unsigned(int32_t, sp->sa_size);
1118 NFSVNO_SETATTRVAL(&nva, size,
1124 rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
1130 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1131 how = fxdr_unsigned(int, *tl);
1133 case NFSCREATE_GUARDED:
1134 case NFSCREATE_UNCHECKED:
1135 error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
1139 case NFSCREATE_EXCLUSIVE:
1140 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
1146 NFSVNO_SETATTRVAL(&nva, type, VREG);
1149 if (nd->nd_repstat) {
1150 nfsvno_relpathbuf(&named);
1151 if (nd->nd_flag & ND_NFSV3) {
1152 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 1,
1154 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1161 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1163 if (nd->nd_flag & ND_NFSV2) {
1167 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1171 if (nd->nd_repstat) {
1172 if (nd->nd_flag & ND_NFSV3)
1173 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1180 if (!(nd->nd_flag & ND_NFSV2)) {
1182 case NFSCREATE_GUARDED:
1184 nd->nd_repstat = EEXIST;
1186 case NFSCREATE_UNCHECKED:
1188 case NFSCREATE_EXCLUSIVE:
1189 if (named.ni_vp == NULL)
1190 NFSVNO_SETATTRVAL(&nva, mode, 0);
1196 * Iff doesn't exist, create it
1197 * otherwise just truncate to 0 length
1198 * should I set the mode too ?
1200 nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
1201 &exclusive_flag, cverf, rdev, exp);
1203 if (!nd->nd_repstat) {
1204 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
1205 if (!nd->nd_repstat)
1206 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
1209 if (!nd->nd_repstat) {
1210 tverf[0] = nva.na_atime.tv_sec;
1211 tverf[1] = nva.na_atime.tv_nsec;
1214 if (nd->nd_flag & ND_NFSV2) {
1215 if (!nd->nd_repstat) {
1216 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
1217 nfsrv_fillattr(nd, &nva);
1220 if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
1221 || cverf[1] != tverf[1]))
1222 nd->nd_repstat = EEXIST;
1223 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1225 if (!nd->nd_repstat) {
1226 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
1227 nfsrv_postopattr(nd, 0, &nva);
1229 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1233 NFSEXITCODE2(0, nd);
1237 nfsvno_relpathbuf(&named);
1238 NFSEXITCODE2(error, nd);
1243 * nfs v3 mknod service (and v4 create)
1246 nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
1247 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
1249 struct nfsvattr nva, dirfor, diraft;
1251 struct nameidata named;
1252 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1253 u_int32_t major, minor;
1254 enum vtype vtyp = VNON;
1255 nfstype nfs4type = NFNON;
1256 vnode_t vp, dirp = NULL;
1257 nfsattrbit_t attrbits;
1258 char *bufp = NULL, *pathcp = NULL;
1259 u_long *hashp, cnflags;
1260 NFSACL_T *aclp = NULL;
1261 struct thread *p = curthread;
1263 NFSVNO_ATTRINIT(&nva);
1264 cnflags = (LOCKPARENT | SAVESTART);
1265 if (nd->nd_repstat) {
1266 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1269 #ifdef NFS4_ACL_EXTATTR_NAME
1270 aclp = acl_alloc(M_WAITOK);
1275 * For V4, the creation stuff is here, Yuck!
1277 if (nd->nd_flag & ND_NFSV4) {
1278 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1279 vtyp = nfsv34tov_type(*tl);
1280 nfs4type = fxdr_unsigned(nfstype, *tl);
1283 error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
1290 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1291 major = fxdr_unsigned(u_int32_t, *tl++);
1292 minor = fxdr_unsigned(u_int32_t, *tl);
1293 nva.na_rdev = NFSMAKEDEV(major, minor);
1299 cnflags = (LOCKPARENT | SAVENAME);
1302 nd->nd_repstat = NFSERR_BADTYPE;
1304 #ifdef NFS4_ACL_EXTATTR_NAME
1310 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags | NOCACHE);
1311 nfsvno_setpathbuf(&named, &bufp, &hashp);
1312 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1315 if (!nd->nd_repstat) {
1316 if (nd->nd_flag & ND_NFSV3) {
1317 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1318 vtyp = nfsv34tov_type(*tl);
1320 error = nfsrv_sattr(nd, NULL, &nva, &attrbits, aclp, p);
1324 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
1325 (vtyp == VCHR || vtyp == VBLK)) {
1326 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1327 major = fxdr_unsigned(u_int32_t, *tl++);
1328 minor = fxdr_unsigned(u_int32_t, *tl);
1329 nva.na_rdev = NFSMAKEDEV(major, minor);
1333 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
1334 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
1335 if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
1336 dirfor.na_gid == nva.na_gid)
1337 NFSVNO_UNSET(&nva, gid);
1338 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
1340 if (nd->nd_repstat) {
1342 #ifdef NFS4_ACL_EXTATTR_NAME
1345 nfsvno_relpathbuf(&named);
1347 free(pathcp, M_TEMP);
1348 if (nd->nd_flag & ND_NFSV3)
1349 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1355 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
1356 * in va_mode, so we'll have to set a default here.
1358 if (NFSVNO_NOTSETMODE(&nva)) {
1366 named.ni_cnd.cn_flags |= WILLBEDIR;
1367 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1368 if (nd->nd_repstat) {
1370 if (nd->nd_flag & ND_NFSV3)
1371 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd,
1375 #ifdef NFS4_ACL_EXTATTR_NAME
1378 if (nd->nd_flag & ND_NFSV3)
1379 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1384 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
1386 if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
1388 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
1389 &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
1391 #ifdef NFS4_ACL_EXTATTR_NAME
1395 } else if (vtyp == VLNK) {
1396 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1397 &dirfor, &diraft, &diraft_ret, &attrbits,
1398 aclp, p, exp, pathcp, pathlen);
1399 #ifdef NFS4_ACL_EXTATTR_NAME
1402 free(pathcp, M_TEMP);
1407 nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
1408 if (!nd->nd_repstat) {
1410 nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
1411 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1412 if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
1413 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
1415 if (vpp != NULL && nd->nd_repstat == 0) {
1422 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1424 if (!nd->nd_repstat) {
1425 if (nd->nd_flag & ND_NFSV3) {
1426 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1427 nfsrv_postopattr(nd, 0, &nva);
1429 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1430 *tl++ = newnfs_false;
1431 txdr_hyper(dirfor.na_filerev, tl);
1433 txdr_hyper(diraft.na_filerev, tl);
1434 (void) nfsrv_putattrbit(nd, &attrbits);
1437 if (nd->nd_flag & ND_NFSV3)
1438 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1439 #ifdef NFS4_ACL_EXTATTR_NAME
1444 NFSEXITCODE2(0, nd);
1448 #ifdef NFS4_ACL_EXTATTR_NAME
1452 nfsvno_relpathbuf(&named);
1454 free(pathcp, M_TEMP);
1456 NFSEXITCODE2(error, nd);
1461 * nfs remove service
1464 nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
1465 vnode_t dp, struct nfsexstuff *exp)
1467 struct nameidata named;
1469 int error = 0, dirfor_ret = 1, diraft_ret = 1;
1470 vnode_t dirp = NULL;
1471 struct nfsvattr dirfor, diraft;
1474 struct thread *p = curthread;
1476 if (nd->nd_repstat) {
1477 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1480 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
1481 LOCKPARENT | LOCKLEAF);
1482 nfsvno_setpathbuf(&named, &bufp, &hashp);
1483 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1486 nfsvno_relpathbuf(&named);
1489 if (!nd->nd_repstat) {
1490 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1493 nfsvno_relpathbuf(&named);
1496 if (!(nd->nd_flag & ND_NFSV2)) {
1497 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1504 if (!nd->nd_repstat) {
1505 if (nd->nd_flag & ND_NFSV4) {
1506 if (vnode_vtype(named.ni_vp) == VDIR)
1507 nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
1508 nd->nd_cred, p, exp);
1510 nd->nd_repstat = nfsvno_removesub(&named, 1,
1511 nd->nd_cred, p, exp);
1512 } else if (nd->nd_procnum == NFSPROC_RMDIR) {
1513 nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
1514 nd->nd_cred, p, exp);
1516 nd->nd_repstat = nfsvno_removesub(&named, 0,
1517 nd->nd_cred, p, exp);
1520 if (!(nd->nd_flag & ND_NFSV2)) {
1522 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0,
1526 if (nd->nd_flag & ND_NFSV3) {
1527 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1529 } else if (!nd->nd_repstat) {
1530 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1531 *tl++ = newnfs_false;
1532 txdr_hyper(dirfor.na_filerev, tl);
1534 txdr_hyper(diraft.na_filerev, tl);
1539 NFSEXITCODE2(error, nd);
1544 * nfs rename service
1547 nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
1548 vnode_t dp, vnode_t todp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
1551 int error = 0, fdirfor_ret = 1, fdiraft_ret = 1;
1552 int tdirfor_ret = 1, tdiraft_ret = 1;
1553 struct nameidata fromnd, tond;
1554 vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
1555 struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
1556 struct nfsexstuff tnes;
1558 char *bufp, *tbufp = NULL;
1561 struct thread *p = curthread;
1563 if (nd->nd_repstat) {
1564 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1565 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1568 if (!(nd->nd_flag & ND_NFSV2))
1569 fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd, p, 1, NULL);
1570 tond.ni_cnd.cn_nameiop = 0;
1571 tond.ni_startdir = NULL;
1572 NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART);
1573 nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
1574 error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
1579 nfsvno_relpathbuf(&fromnd);
1583 * Unlock dp in this code section, so it is unlocked before
1584 * tdp gets locked. This avoids a potential LOR if tdp is the
1585 * parent directory of dp.
1587 if (nd->nd_flag & ND_NFSV4) {
1592 /* Might lock tdp. */
1593 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 0,
1596 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1,
1601 tfh.nfsrvfh_len = 0;
1602 error = nfsrv_mtofh(nd, &tfh);
1604 error = nfsvno_getfh(dp, &fh, p);
1607 /* todp is always NULL except NFSv4 */
1608 nfsvno_relpathbuf(&fromnd);
1612 /* If this is the same file handle, just VREF() the vnode. */
1613 if (tfh.nfsrvfh_len == NFSX_MYFH &&
1614 !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
1618 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1,
1623 nd->nd_cred->cr_uid = nd->nd_saveduid;
1624 nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
1625 0); /* Locks tdp. */
1627 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd,
1633 NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
1634 nfsvno_setpathbuf(&tond, &tbufp, &hashp);
1635 if (!nd->nd_repstat) {
1636 error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
1641 nfsvno_relpathbuf(&fromnd);
1642 nfsvno_relpathbuf(&tond);
1646 if (nd->nd_repstat) {
1647 if (nd->nd_flag & ND_NFSV3) {
1648 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1650 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1656 nfsvno_relpathbuf(&fromnd);
1657 nfsvno_relpathbuf(&tond);
1662 * Done parsing, now down to business.
1664 nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, p, &fdirp);
1665 if (nd->nd_repstat) {
1666 if (nd->nd_flag & ND_NFSV3) {
1667 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1669 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1676 nfsvno_relpathbuf(&tond);
1679 if (vnode_vtype(fromnd.ni_vp) == VDIR)
1680 tond.ni_cnd.cn_flags |= WILLBEDIR;
1681 nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
1682 nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
1683 nd->nd_flag, nd->nd_cred, p);
1685 fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd, p, 0, NULL);
1687 tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd, p, 0, NULL);
1692 if (nd->nd_flag & ND_NFSV3) {
1693 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1694 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1695 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1696 NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
1697 *tl++ = newnfs_false;
1698 txdr_hyper(fdirfor.na_filerev, tl);
1700 txdr_hyper(fdiraft.na_filerev, tl);
1702 *tl++ = newnfs_false;
1703 txdr_hyper(tdirfor.na_filerev, tl);
1705 txdr_hyper(tdiraft.na_filerev, tl);
1709 NFSEXITCODE2(error, nd);
1717 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
1718 vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
1720 struct nameidata named;
1722 int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
1723 vnode_t dirp = NULL, dp = NULL;
1724 struct nfsvattr dirfor, diraft, at;
1725 struct nfsexstuff tnes;
1729 struct thread *p = curthread;
1731 if (nd->nd_repstat) {
1732 nfsrv_postopattr(nd, getret, &at);
1733 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1737 if (vnode_vtype(vp) == VDIR) {
1738 if (nd->nd_flag & ND_NFSV4)
1739 nd->nd_repstat = NFSERR_ISDIR;
1741 nd->nd_repstat = NFSERR_INVAL;
1745 if (!nd->nd_repstat) {
1746 if (nd->nd_flag & ND_NFSV4) {
1750 error = nfsrv_mtofh(nd, &dfh);
1753 /* tovp is always NULL unless NFSv4 */
1756 nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0);
1761 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1762 LOCKPARENT | SAVENAME | NOCACHE);
1763 if (!nd->nd_repstat) {
1764 nfsvno_setpathbuf(&named, &bufp, &hashp);
1765 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1770 nfsvno_relpathbuf(&named);
1773 if (!nd->nd_repstat) {
1774 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
1779 nfsvno_relpathbuf(&named);
1783 if (nd->nd_flag & ND_NFSV2) {
1787 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1791 if (!nd->nd_repstat)
1792 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
1793 if (nd->nd_flag & ND_NFSV3)
1794 getret = nfsvno_getattr(vp, &at, nd, p, 0, NULL);
1796 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1800 if (nd->nd_flag & ND_NFSV3) {
1801 nfsrv_postopattr(nd, getret, &at);
1802 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1803 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1804 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1805 *tl++ = newnfs_false;
1806 txdr_hyper(dirfor.na_filerev, tl);
1808 txdr_hyper(diraft.na_filerev, tl);
1812 NFSEXITCODE2(error, nd);
1817 * nfs symbolic link service
1820 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1821 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
1823 struct nfsvattr nva, dirfor, diraft;
1824 struct nameidata named;
1825 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1826 vnode_t dirp = NULL;
1827 char *bufp, *pathcp = NULL;
1829 struct thread *p = curthread;
1831 if (nd->nd_repstat) {
1832 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1837 NFSVNO_ATTRINIT(&nva);
1838 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1839 LOCKPARENT | SAVESTART | NOCACHE);
1840 nfsvno_setpathbuf(&named, &bufp, &hashp);
1841 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1842 if (!error && !nd->nd_repstat)
1843 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
1846 nfsvno_relpathbuf(&named);
1849 if (!nd->nd_repstat) {
1850 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1853 nfsvno_relpathbuf(&named);
1855 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1861 * And call nfsrvd_symlinksub() to do the common code. It will
1862 * return EBADRPC upon a parsing error, 0 otherwise.
1864 if (!nd->nd_repstat) {
1866 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1868 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1869 &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
1871 } else if (dirp != NULL) {
1872 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
1876 free(pathcp, M_TEMP);
1878 if (nd->nd_flag & ND_NFSV3) {
1879 if (!nd->nd_repstat) {
1880 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1881 nfsrv_postopattr(nd, 0, &nva);
1883 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1887 NFSEXITCODE2(error, nd);
1892 * Common code for creating a symbolic link.
1895 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
1896 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1897 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1898 int *diraft_retp, nfsattrbit_t *attrbitp,
1899 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
1904 nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
1905 !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
1906 if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
1907 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
1908 if (nd->nd_flag & ND_NFSV3) {
1909 nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
1910 if (!nd->nd_repstat)
1911 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
1912 nvap, nd, p, 1, NULL);
1914 if (vpp != NULL && nd->nd_repstat == 0) {
1915 NFSVOPUNLOCK(ndp->ni_vp);
1921 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL);
1924 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1925 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1926 *tl++ = newnfs_false;
1927 txdr_hyper(dirforp->na_filerev, tl);
1929 txdr_hyper(diraftp->na_filerev, tl);
1930 (void) nfsrv_putattrbit(nd, attrbitp);
1933 NFSEXITCODE2(0, nd);
1940 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
1941 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
1943 struct nfsvattr nva, dirfor, diraft;
1944 struct nameidata named;
1946 int error = 0, dirfor_ret = 1, diraft_ret = 1;
1947 vnode_t dirp = NULL;
1950 struct thread *p = curthread;
1952 if (nd->nd_repstat) {
1953 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1956 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1957 LOCKPARENT | SAVENAME | NOCACHE);
1958 nfsvno_setpathbuf(&named, &bufp, &hashp);
1959 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1962 if (!nd->nd_repstat) {
1963 NFSVNO_ATTRINIT(&nva);
1964 if (nd->nd_flag & ND_NFSV3) {
1965 error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
1969 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1970 nva.na_mode = nfstov_mode(*tl++);
1973 if (!nd->nd_repstat) {
1974 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1977 nfsvno_relpathbuf(&named);
1979 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1983 if (nd->nd_repstat) {
1985 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1989 if (nd->nd_flag & ND_NFSV3)
1990 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1995 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
1998 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
2000 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
2001 &diraft_ret, NULL, NULL, p, exp);
2003 if (nd->nd_flag & ND_NFSV3) {
2004 if (!nd->nd_repstat) {
2005 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
2006 nfsrv_postopattr(nd, 0, &nva);
2008 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
2009 } else if (!nd->nd_repstat) {
2010 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2011 nfsrv_fillattr(nd, &nva);
2015 NFSEXITCODE2(0, nd);
2019 nfsvno_relpathbuf(&named);
2020 NFSEXITCODE2(error, nd);
2025 * Code common to mkdir for V2,3 and 4.
2028 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
2029 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
2030 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
2031 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
2032 NFSPROC_T *p, struct nfsexstuff *exp)
2037 NFSVNO_SETATTRVAL(nvap, type, VDIR);
2038 nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
2039 nd->nd_cred, p, exp);
2040 if (!nd->nd_repstat) {
2042 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
2043 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
2044 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
2045 nd->nd_repstat = nfsvno_getattr(vp, nvap, nd, p, 1,
2047 if (vpp && !nd->nd_repstat) {
2055 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL);
2058 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
2059 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2060 *tl++ = newnfs_false;
2061 txdr_hyper(dirforp->na_filerev, tl);
2063 txdr_hyper(diraftp->na_filerev, tl);
2064 (void) nfsrv_putattrbit(nd, attrbitp);
2067 NFSEXITCODE2(0, nd);
2071 * nfs commit service
2074 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
2075 vnode_t vp, __unused struct nfsexstuff *exp)
2077 struct nfsvattr bfor, aft;
2079 int error = 0, for_ret = 1, aft_ret = 1, cnt;
2081 struct thread *p = curthread;
2083 if (nd->nd_repstat) {
2084 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
2088 /* Return NFSERR_ISDIR in NFSv4 when commit on a directory. */
2089 if (vp->v_type != VREG) {
2090 if (nd->nd_flag & ND_NFSV3)
2091 error = NFSERR_NOTSUPP;
2093 error = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_INVAL;
2096 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2099 * XXX At this time VOP_FSYNC() does not accept offset and byte
2100 * count parameters, so these arguments are useless (someday maybe).
2102 off = fxdr_hyper(tl);
2104 cnt = fxdr_unsigned(int, *tl);
2105 if (nd->nd_flag & ND_NFSV3)
2106 for_ret = nfsvno_getattr(vp, &bfor, nd, p, 1, NULL);
2107 nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
2108 if (nd->nd_flag & ND_NFSV3) {
2109 aft_ret = nfsvno_getattr(vp, &aft, nd, p, 1, NULL);
2110 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
2113 if (!nd->nd_repstat) {
2114 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2115 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
2116 *tl = txdr_unsigned(nfsboottime.tv_usec);
2120 NFSEXITCODE2(0, nd);
2124 NFSEXITCODE2(error, nd);
2129 * nfs statfs service
2132 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
2133 vnode_t vp, __unused struct nfsexstuff *exp)
2140 struct thread *p = curthread;
2143 if (nd->nd_repstat) {
2144 nfsrv_postopattr(nd, getret, &at);
2147 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2148 nd->nd_repstat = nfsvno_statfs(vp, sf);
2149 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2151 if (nd->nd_flag & ND_NFSV3)
2152 nfsrv_postopattr(nd, getret, &at);
2155 if (nd->nd_flag & ND_NFSV2) {
2156 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
2157 *tl++ = txdr_unsigned(NFS_V2MAXDATA);
2158 *tl++ = txdr_unsigned(sf->f_bsize);
2159 *tl++ = txdr_unsigned(sf->f_blocks);
2160 *tl++ = txdr_unsigned(sf->f_bfree);
2161 *tl = txdr_unsigned(sf->f_bavail);
2163 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
2164 tval = (u_quad_t)sf->f_blocks;
2165 tval *= (u_quad_t)sf->f_bsize;
2166 txdr_hyper(tval, tl); tl += 2;
2167 tval = (u_quad_t)sf->f_bfree;
2168 tval *= (u_quad_t)sf->f_bsize;
2169 txdr_hyper(tval, tl); tl += 2;
2170 tval = (u_quad_t)sf->f_bavail;
2171 tval *= (u_quad_t)sf->f_bsize;
2172 txdr_hyper(tval, tl); tl += 2;
2173 tval = (u_quad_t)sf->f_files;
2174 txdr_hyper(tval, tl); tl += 2;
2175 tval = (u_quad_t)sf->f_ffree;
2176 txdr_hyper(tval, tl); tl += 2;
2177 tval = (u_quad_t)sf->f_ffree;
2178 txdr_hyper(tval, tl); tl += 2;
2184 NFSEXITCODE2(0, nd);
2189 * nfs fsinfo service
2192 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
2193 vnode_t vp, __unused struct nfsexstuff *exp)
2196 struct nfsfsinfo fs;
2199 struct thread *p = curthread;
2201 if (nd->nd_repstat) {
2202 nfsrv_postopattr(nd, getret, &at);
2205 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2206 nfsvno_getfs(&fs, isdgram);
2208 nfsrv_postopattr(nd, getret, &at);
2209 NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
2210 *tl++ = txdr_unsigned(fs.fs_rtmax);
2211 *tl++ = txdr_unsigned(fs.fs_rtpref);
2212 *tl++ = txdr_unsigned(fs.fs_rtmult);
2213 *tl++ = txdr_unsigned(fs.fs_wtmax);
2214 *tl++ = txdr_unsigned(fs.fs_wtpref);
2215 *tl++ = txdr_unsigned(fs.fs_wtmult);
2216 *tl++ = txdr_unsigned(fs.fs_dtpref);
2217 txdr_hyper(fs.fs_maxfilesize, tl);
2219 txdr_nfsv3time(&fs.fs_timedelta, tl);
2221 *tl = txdr_unsigned(fs.fs_properties);
2224 NFSEXITCODE2(0, nd);
2229 * nfs pathconf service
2232 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
2233 vnode_t vp, __unused struct nfsexstuff *exp)
2235 struct nfsv3_pathconf *pc;
2237 long linkmax, namemax, chownres, notrunc;
2239 struct thread *p = curthread;
2241 if (nd->nd_repstat) {
2242 nfsrv_postopattr(nd, getret, &at);
2245 nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
2247 if (!nd->nd_repstat)
2248 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
2250 if (!nd->nd_repstat)
2251 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
2252 &chownres, nd->nd_cred, p);
2253 if (!nd->nd_repstat)
2254 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc,
2256 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2258 nfsrv_postopattr(nd, getret, &at);
2259 if (!nd->nd_repstat) {
2260 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
2261 pc->pc_linkmax = txdr_unsigned(linkmax);
2262 pc->pc_namemax = txdr_unsigned(namemax);
2263 pc->pc_notrunc = txdr_unsigned(notrunc);
2264 pc->pc_chownrestricted = txdr_unsigned(chownres);
2267 * These should probably be supported by VOP_PATHCONF(), but
2268 * until msdosfs is exportable (why would you want to?), the
2269 * Unix defaults should be ok.
2271 pc->pc_caseinsensitive = newnfs_false;
2272 pc->pc_casepreserving = newnfs_true;
2276 NFSEXITCODE2(0, nd);
2281 * nfsv4 lock service
2284 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2285 vnode_t vp, struct nfsexstuff *exp)
2289 struct nfsstate *stp = NULL;
2290 struct nfslock *lop;
2291 struct nfslockconflict cf;
2293 u_short flags = NFSLCK_LOCK, lflags;
2294 u_int64_t offset, len;
2295 nfsv4stateid_t stateid;
2297 struct thread *p = curthread;
2299 NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2300 i = fxdr_unsigned(int, *tl++);
2302 case NFSV4LOCKT_READW:
2303 flags |= NFSLCK_BLOCKING;
2304 case NFSV4LOCKT_READ:
2305 lflags = NFSLCK_READ;
2307 case NFSV4LOCKT_WRITEW:
2308 flags |= NFSLCK_BLOCKING;
2309 case NFSV4LOCKT_WRITE:
2310 lflags = NFSLCK_WRITE;
2313 nd->nd_repstat = NFSERR_BADXDR;
2316 if (*tl++ == newnfs_true)
2317 flags |= NFSLCK_RECLAIM;
2318 offset = fxdr_hyper(tl);
2320 len = fxdr_hyper(tl);
2322 if (*tl == newnfs_true)
2323 flags |= NFSLCK_OPENTOLOCK;
2324 if (flags & NFSLCK_OPENTOLOCK) {
2325 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2326 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2327 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2328 nd->nd_repstat = NFSERR_BADXDR;
2331 stp = malloc(sizeof (struct nfsstate) + i,
2332 M_NFSDSTATE, M_WAITOK);
2333 stp->ls_ownerlen = i;
2334 stp->ls_op = nd->nd_rp;
2335 stp->ls_seq = fxdr_unsigned(int, *tl++);
2336 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2337 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2339 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2342 * For the special stateid of other all 0s and seqid == 1, set
2343 * the stateid to the current stateid, if it is set.
2345 if ((nd->nd_flag & ND_NFSV41) != 0 &&
2346 stp->ls_stateid.seqid == 1 &&
2347 stp->ls_stateid.other[0] == 0 &&
2348 stp->ls_stateid.other[1] == 0 &&
2349 stp->ls_stateid.other[2] == 0) {
2350 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2351 stp->ls_stateid = nd->nd_curstateid;
2352 stp->ls_stateid.seqid = 0;
2354 nd->nd_repstat = NFSERR_BADSTATEID;
2359 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2360 clientid.lval[0] = *tl++;
2361 clientid.lval[1] = *tl++;
2362 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2363 if ((nd->nd_flag & ND_NFSV41) != 0)
2364 clientid.qval = nd->nd_clientid.qval;
2365 else if (nd->nd_clientid.qval != clientid.qval)
2366 printf("EEK3 multiple clids\n");
2368 if ((nd->nd_flag & ND_NFSV41) != 0)
2369 printf("EEK! no clientid from session\n");
2370 nd->nd_flag |= ND_IMPLIEDCLID;
2371 nd->nd_clientid.qval = clientid.qval;
2373 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2377 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2378 stp = malloc(sizeof (struct nfsstate),
2379 M_NFSDSTATE, M_WAITOK);
2380 stp->ls_ownerlen = 0;
2381 stp->ls_op = nd->nd_rp;
2382 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2383 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2385 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2388 * For the special stateid of other all 0s and seqid == 1, set
2389 * the stateid to the current stateid, if it is set.
2391 if ((nd->nd_flag & ND_NFSV41) != 0 &&
2392 stp->ls_stateid.seqid == 1 &&
2393 stp->ls_stateid.other[0] == 0 &&
2394 stp->ls_stateid.other[1] == 0 &&
2395 stp->ls_stateid.other[2] == 0) {
2396 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2397 stp->ls_stateid = nd->nd_curstateid;
2398 stp->ls_stateid.seqid = 0;
2400 nd->nd_repstat = NFSERR_BADSTATEID;
2405 stp->ls_seq = fxdr_unsigned(int, *tl);
2406 clientid.lval[0] = stp->ls_stateid.other[0];
2407 clientid.lval[1] = stp->ls_stateid.other[1];
2408 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2409 if ((nd->nd_flag & ND_NFSV41) != 0)
2410 clientid.qval = nd->nd_clientid.qval;
2411 else if (nd->nd_clientid.qval != clientid.qval)
2412 printf("EEK4 multiple clids\n");
2414 if ((nd->nd_flag & ND_NFSV41) != 0)
2415 printf("EEK! no clientid from session\n");
2416 nd->nd_flag |= ND_IMPLIEDCLID;
2417 nd->nd_clientid.qval = clientid.qval;
2420 lop = malloc(sizeof (struct nfslock),
2421 M_NFSDLOCK, M_WAITOK);
2422 lop->lo_first = offset;
2423 if (len == NFS64BITSSET) {
2424 lop->lo_end = NFS64BITSSET;
2426 lop->lo_end = offset + len;
2427 if (lop->lo_end <= lop->lo_first)
2428 nd->nd_repstat = NFSERR_INVAL;
2430 lop->lo_flags = lflags;
2431 stp->ls_flags = flags;
2432 stp->ls_uid = nd->nd_cred->cr_uid;
2435 * Do basic access checking.
2437 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2438 if (vnode_vtype(vp) == VDIR)
2439 nd->nd_repstat = NFSERR_ISDIR;
2441 nd->nd_repstat = NFSERR_INVAL;
2443 if (!nd->nd_repstat) {
2444 if (lflags & NFSLCK_WRITE) {
2445 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
2446 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2447 NFSACCCHK_VPISLOCKED, NULL);
2449 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
2450 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2451 NFSACCCHK_VPISLOCKED, NULL);
2453 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2454 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2455 NFSACCCHK_VPISLOCKED, NULL);
2460 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
2461 * seqid# gets updated. nfsrv_lockctrl() will return the value
2462 * of nd_repstat, if it gets that far.
2464 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2465 &stateid, exp, nd, p);
2467 free(lop, M_NFSDLOCK);
2469 free(stp, M_NFSDSTATE);
2470 if (!nd->nd_repstat) {
2471 /* For NFSv4.1, set the Current StateID. */
2472 if ((nd->nd_flag & ND_NFSV41) != 0) {
2473 nd->nd_curstateid = stateid;
2474 nd->nd_flag |= ND_CURSTATEID;
2476 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2477 *tl++ = txdr_unsigned(stateid.seqid);
2478 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2479 } else if (nd->nd_repstat == NFSERR_DENIED) {
2480 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2481 txdr_hyper(cf.cl_first, tl);
2483 if (cf.cl_end == NFS64BITSSET)
2486 len = cf.cl_end - cf.cl_first;
2487 txdr_hyper(len, tl);
2489 if (cf.cl_flags == NFSLCK_WRITE)
2490 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2492 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2493 *tl++ = stateid.other[0];
2494 *tl = stateid.other[1];
2495 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2498 NFSEXITCODE2(0, nd);
2503 free(stp, M_NFSDSTATE);
2504 NFSEXITCODE2(error, nd);
2509 * nfsv4 lock test service
2512 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2513 vnode_t vp, struct nfsexstuff *exp)
2517 struct nfsstate *stp = NULL;
2518 struct nfslock lo, *lop = &lo;
2519 struct nfslockconflict cf;
2521 nfsv4stateid_t stateid;
2524 struct thread *p = curthread;
2526 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2527 i = fxdr_unsigned(int, *(tl + 7));
2528 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2529 nd->nd_repstat = NFSERR_BADXDR;
2532 stp = malloc(sizeof (struct nfsstate) + i,
2533 M_NFSDSTATE, M_WAITOK);
2534 stp->ls_ownerlen = i;
2536 stp->ls_flags = NFSLCK_TEST;
2537 stp->ls_uid = nd->nd_cred->cr_uid;
2538 i = fxdr_unsigned(int, *tl++);
2540 case NFSV4LOCKT_READW:
2541 stp->ls_flags |= NFSLCK_BLOCKING;
2542 case NFSV4LOCKT_READ:
2543 lo.lo_flags = NFSLCK_READ;
2545 case NFSV4LOCKT_WRITEW:
2546 stp->ls_flags |= NFSLCK_BLOCKING;
2547 case NFSV4LOCKT_WRITE:
2548 lo.lo_flags = NFSLCK_WRITE;
2551 nd->nd_repstat = NFSERR_BADXDR;
2554 lo.lo_first = fxdr_hyper(tl);
2556 len = fxdr_hyper(tl);
2557 if (len == NFS64BITSSET) {
2558 lo.lo_end = NFS64BITSSET;
2560 lo.lo_end = lo.lo_first + len;
2561 if (lo.lo_end <= lo.lo_first)
2562 nd->nd_repstat = NFSERR_INVAL;
2565 clientid.lval[0] = *tl++;
2566 clientid.lval[1] = *tl;
2567 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2568 if ((nd->nd_flag & ND_NFSV41) != 0)
2569 clientid.qval = nd->nd_clientid.qval;
2570 else if (nd->nd_clientid.qval != clientid.qval)
2571 printf("EEK5 multiple clids\n");
2573 if ((nd->nd_flag & ND_NFSV41) != 0)
2574 printf("EEK! no clientid from session\n");
2575 nd->nd_flag |= ND_IMPLIEDCLID;
2576 nd->nd_clientid.qval = clientid.qval;
2578 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2581 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2582 if (vnode_vtype(vp) == VDIR)
2583 nd->nd_repstat = NFSERR_ISDIR;
2585 nd->nd_repstat = NFSERR_INVAL;
2587 if (!nd->nd_repstat)
2588 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2589 &stateid, exp, nd, p);
2590 if (nd->nd_repstat) {
2591 if (nd->nd_repstat == NFSERR_DENIED) {
2592 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2593 txdr_hyper(cf.cl_first, tl);
2595 if (cf.cl_end == NFS64BITSSET)
2598 len = cf.cl_end - cf.cl_first;
2599 txdr_hyper(len, tl);
2601 if (cf.cl_flags == NFSLCK_WRITE)
2602 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2604 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2605 *tl++ = stp->ls_stateid.other[0];
2606 *tl = stp->ls_stateid.other[1];
2607 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2612 free(stp, M_NFSDSTATE);
2613 NFSEXITCODE2(0, nd);
2618 free(stp, M_NFSDSTATE);
2619 NFSEXITCODE2(error, nd);
2624 * nfsv4 unlock service
2627 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2628 vnode_t vp, struct nfsexstuff *exp)
2632 struct nfsstate *stp;
2633 struct nfslock *lop;
2635 nfsv4stateid_t stateid;
2638 struct thread *p = curthread;
2640 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2641 stp = malloc(sizeof (struct nfsstate),
2642 M_NFSDSTATE, M_WAITOK);
2643 lop = malloc(sizeof (struct nfslock),
2644 M_NFSDLOCK, M_WAITOK);
2645 stp->ls_flags = NFSLCK_UNLOCK;
2646 lop->lo_flags = NFSLCK_UNLOCK;
2647 stp->ls_op = nd->nd_rp;
2648 i = fxdr_unsigned(int, *tl++);
2650 case NFSV4LOCKT_READW:
2651 stp->ls_flags |= NFSLCK_BLOCKING;
2652 case NFSV4LOCKT_READ:
2654 case NFSV4LOCKT_WRITEW:
2655 stp->ls_flags |= NFSLCK_BLOCKING;
2656 case NFSV4LOCKT_WRITE:
2659 nd->nd_repstat = NFSERR_BADXDR;
2660 free(stp, M_NFSDSTATE);
2661 free(lop, M_NFSDLOCK);
2664 stp->ls_ownerlen = 0;
2665 stp->ls_uid = nd->nd_cred->cr_uid;
2666 stp->ls_seq = fxdr_unsigned(int, *tl++);
2667 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2668 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2670 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2673 * For the special stateid of other all 0s and seqid == 1, set the
2674 * stateid to the current stateid, if it is set.
2676 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
2677 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
2678 stp->ls_stateid.other[2] == 0) {
2679 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2680 stp->ls_stateid = nd->nd_curstateid;
2681 stp->ls_stateid.seqid = 0;
2683 nd->nd_repstat = NFSERR_BADSTATEID;
2688 lop->lo_first = fxdr_hyper(tl);
2690 len = fxdr_hyper(tl);
2691 if (len == NFS64BITSSET) {
2692 lop->lo_end = NFS64BITSSET;
2694 lop->lo_end = lop->lo_first + len;
2695 if (lop->lo_end <= lop->lo_first)
2696 nd->nd_repstat = NFSERR_INVAL;
2698 clientid.lval[0] = stp->ls_stateid.other[0];
2699 clientid.lval[1] = stp->ls_stateid.other[1];
2700 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2701 if ((nd->nd_flag & ND_NFSV41) != 0)
2702 clientid.qval = nd->nd_clientid.qval;
2703 else if (nd->nd_clientid.qval != clientid.qval)
2704 printf("EEK6 multiple clids\n");
2706 if ((nd->nd_flag & ND_NFSV41) != 0)
2707 printf("EEK! no clientid from session\n");
2708 nd->nd_flag |= ND_IMPLIEDCLID;
2709 nd->nd_clientid.qval = clientid.qval;
2711 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2712 if (vnode_vtype(vp) == VDIR)
2713 nd->nd_repstat = NFSERR_ISDIR;
2715 nd->nd_repstat = NFSERR_INVAL;
2718 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2719 * seqid# gets incremented. nfsrv_lockctrl() will return the
2720 * value of nd_repstat, if it gets that far.
2722 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2723 &stateid, exp, nd, p);
2725 free(stp, M_NFSDSTATE);
2727 free(lop, M_NFSDLOCK);
2728 if (!nd->nd_repstat) {
2729 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2730 *tl++ = txdr_unsigned(stateid.seqid);
2731 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2735 NFSEXITCODE2(error, nd);
2740 * nfsv4 open service
2743 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2744 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, struct nfsexstuff *exp)
2748 struct nfsstate *stp = NULL;
2749 int error = 0, create, claim, exclusive_flag = 0, override;
2750 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2751 int how = NFSCREATE_UNCHECKED;
2752 int32_t cverf[2], tverf[2] = { 0, 0 };
2753 vnode_t vp = NULL, dirp = NULL;
2754 struct nfsvattr nva, dirfor, diraft;
2755 struct nameidata named;
2756 nfsv4stateid_t stateid, delegstateid;
2757 nfsattrbit_t attrbits;
2761 NFSACL_T *aclp = NULL;
2762 struct thread *p = curthread;
2764 #ifdef NFS4_ACL_EXTATTR_NAME
2765 aclp = acl_alloc(M_WAITOK);
2768 NFSZERO_ATTRBIT(&attrbits);
2769 named.ni_startdir = NULL;
2770 named.ni_cnd.cn_nameiop = 0;
2771 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2772 i = fxdr_unsigned(int, *(tl + 5));
2773 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2774 nd->nd_repstat = NFSERR_BADXDR;
2777 stp = malloc(sizeof (struct nfsstate) + i,
2778 M_NFSDSTATE, M_WAITOK);
2779 stp->ls_ownerlen = i;
2780 stp->ls_op = nd->nd_rp;
2781 stp->ls_flags = NFSLCK_OPEN;
2782 stp->ls_uid = nd->nd_cred->cr_uid;
2783 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2784 i = fxdr_unsigned(int, *tl++);
2786 if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG |
2787 NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) {
2789 /* For now, ignore these. */
2790 i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG);
2791 switch (i & NFSV4OPEN_WANTDELEGMASK) {
2792 case NFSV4OPEN_WANTANYDELEG:
2793 stp->ls_flags |= (NFSLCK_WANTRDELEG |
2795 i &= ~NFSV4OPEN_WANTDELEGMASK;
2797 case NFSV4OPEN_WANTREADDELEG:
2798 stp->ls_flags |= NFSLCK_WANTRDELEG;
2799 i &= ~NFSV4OPEN_WANTDELEGMASK;
2801 case NFSV4OPEN_WANTWRITEDELEG:
2802 stp->ls_flags |= NFSLCK_WANTWDELEG;
2803 i &= ~NFSV4OPEN_WANTDELEGMASK;
2805 case NFSV4OPEN_WANTNODELEG:
2806 stp->ls_flags |= NFSLCK_WANTNODELEG;
2807 i &= ~NFSV4OPEN_WANTDELEGMASK;
2809 case NFSV4OPEN_WANTCANCEL:
2810 printf("NFSv4: ignore Open WantCancel\n");
2811 i &= ~NFSV4OPEN_WANTDELEGMASK;
2814 /* nd_repstat will be set to NFSERR_INVAL below. */
2819 case NFSV4OPEN_ACCESSREAD:
2820 stp->ls_flags |= NFSLCK_READACCESS;
2822 case NFSV4OPEN_ACCESSWRITE:
2823 stp->ls_flags |= NFSLCK_WRITEACCESS;
2825 case NFSV4OPEN_ACCESSBOTH:
2826 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2829 nd->nd_repstat = NFSERR_INVAL;
2831 i = fxdr_unsigned(int, *tl++);
2833 case NFSV4OPEN_DENYNONE:
2835 case NFSV4OPEN_DENYREAD:
2836 stp->ls_flags |= NFSLCK_READDENY;
2838 case NFSV4OPEN_DENYWRITE:
2839 stp->ls_flags |= NFSLCK_WRITEDENY;
2841 case NFSV4OPEN_DENYBOTH:
2842 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
2845 nd->nd_repstat = NFSERR_INVAL;
2847 clientid.lval[0] = *tl++;
2848 clientid.lval[1] = *tl;
2849 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2850 if ((nd->nd_flag & ND_NFSV41) != 0)
2851 clientid.qval = nd->nd_clientid.qval;
2852 else if (nd->nd_clientid.qval != clientid.qval)
2853 printf("EEK7 multiple clids\n");
2855 if ((nd->nd_flag & ND_NFSV41) != 0)
2856 printf("EEK! no clientid from session\n");
2857 nd->nd_flag |= ND_IMPLIEDCLID;
2858 nd->nd_clientid.qval = clientid.qval;
2860 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2863 NFSVNO_ATTRINIT(&nva);
2864 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2865 create = fxdr_unsigned(int, *tl);
2866 if (!nd->nd_repstat)
2867 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
2868 if (create == NFSV4OPEN_CREATE) {
2871 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2872 how = fxdr_unsigned(int, *tl);
2874 case NFSCREATE_UNCHECKED:
2875 case NFSCREATE_GUARDED:
2876 error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
2880 * If the na_gid being set is the same as that of
2881 * the directory it is going in, clear it, since
2882 * that is what will be set by default. This allows
2883 * a user that isn't in that group to do the create.
2885 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
2886 nva.na_gid == dirfor.na_gid)
2887 NFSVNO_UNSET(&nva, gid);
2888 if (!nd->nd_repstat)
2889 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2891 case NFSCREATE_EXCLUSIVE:
2892 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2896 case NFSCREATE_EXCLUSIVE41:
2897 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2900 error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
2903 if (NFSISSET_ATTRBIT(&attrbits,
2904 NFSATTRBIT_TIMEACCESSSET))
2905 nd->nd_repstat = NFSERR_INVAL;
2907 * If the na_gid being set is the same as that of
2908 * the directory it is going in, clear it, since
2909 * that is what will be set by default. This allows
2910 * a user that isn't in that group to do the create.
2912 if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) &&
2913 nva.na_gid == dirfor.na_gid)
2914 NFSVNO_UNSET(&nva, gid);
2915 if (nd->nd_repstat == 0)
2916 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2919 nd->nd_repstat = NFSERR_BADXDR;
2922 } else if (create != NFSV4OPEN_NOCREATE) {
2923 nd->nd_repstat = NFSERR_BADXDR;
2928 * Now, handle the claim, which usually includes looking up a
2929 * name in the directory referenced by dp. The exception is
2930 * NFSV4OPEN_CLAIMPREVIOUS.
2932 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2933 claim = fxdr_unsigned(int, *tl);
2934 if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
2935 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2936 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2937 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
2938 stp->ls_flags |= NFSLCK_DELEGCUR;
2939 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2940 stp->ls_flags |= NFSLCK_DELEGPREV;
2942 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
2943 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2944 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
2945 claim != NFSV4OPEN_CLAIMNULL)
2946 nd->nd_repstat = NFSERR_INVAL;
2947 if (nd->nd_repstat) {
2948 nd->nd_repstat = nfsrv_opencheck(clientid,
2949 &stateid, stp, NULL, nd, p, nd->nd_repstat);
2952 if (create == NFSV4OPEN_CREATE)
2953 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
2954 LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
2956 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
2957 LOCKLEAF | SAVESTART);
2958 nfsvno_setpathbuf(&named, &bufp, &hashp);
2959 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2962 #ifdef NFS4_ACL_EXTATTR_NAME
2965 free(stp, M_NFSDSTATE);
2966 nfsvno_relpathbuf(&named);
2967 NFSEXITCODE2(error, nd);
2970 if (!nd->nd_repstat) {
2971 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
2975 nfsvno_relpathbuf(&named);
2977 if (create == NFSV4OPEN_CREATE) {
2979 case NFSCREATE_UNCHECKED:
2982 * Clear the setable attribute bits, except
2983 * for Size, if it is being truncated.
2985 NFSZERO_ATTRBIT(&attrbits);
2986 if (NFSVNO_ISSETSIZE(&nva))
2987 NFSSETBIT_ATTRBIT(&attrbits,
2991 case NFSCREATE_GUARDED:
2992 if (named.ni_vp && !nd->nd_repstat)
2993 nd->nd_repstat = EEXIST;
2995 case NFSCREATE_EXCLUSIVE:
3000 case NFSCREATE_EXCLUSIVE41:
3005 nfsvno_open(nd, &named, clientid, &stateid, stp,
3006 &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
3007 nd->nd_cred, exp, &vp);
3008 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim ==
3009 NFSV4OPEN_CLAIMFH) {
3010 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
3011 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3012 i = fxdr_unsigned(int, *tl);
3014 case NFSV4OPEN_DELEGATEREAD:
3015 stp->ls_flags |= NFSLCK_DELEGREAD;
3017 case NFSV4OPEN_DELEGATEWRITE:
3018 stp->ls_flags |= NFSLCK_DELEGWRITE;
3019 case NFSV4OPEN_DELEGATENONE:
3022 nd->nd_repstat = NFSERR_BADXDR;
3025 stp->ls_flags |= NFSLCK_RECLAIM;
3028 if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE)
3029 nd->nd_repstat = NFSERR_INVAL;
3032 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
3033 if (!VN_IS_DOOMED(vp))
3034 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
3035 stp, vp, nd, p, nd->nd_repstat);
3037 nd->nd_repstat = NFSERR_PERM;
3039 nd->nd_repstat = NFSERR_BADXDR;
3044 * Do basic access checking.
3046 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
3048 * The IETF working group decided that this is the correct
3049 * error return for all non-regular files.
3051 nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK;
3055 * If the Open is being done for a file that already exists, apply
3056 * normal permission checking including for the file owner, if
3057 * vfs.nfsd.v4openaccess is set.
3058 * Previously, the owner was always allowed to open the file to
3059 * be consistent with the NFS tradition of always allowing the
3060 * owner of the file to write to the file regardless of permissions.
3061 * It now appears that the Linux client expects the owner
3062 * permissions to be checked for opens that are not creating the
3063 * file. I believe the correct approach is to use the Access
3064 * operation's results to be consistent with NFSv3, but that is
3065 * not what the current Linux client appears to be doing.
3066 * Since both the Linux and OpenSolaris NFSv4 servers do this check,
3067 * I have enabled it by default.
3068 * If this semantic change causes a problem, it can be disabled by
3069 * setting the sysctl vfs.nfsd.v4openaccess to 0 to re-enable the
3070 * previous semantics.
3072 if (nfsrv_openaccess && create == NFSV4OPEN_NOCREATE)
3073 override = NFSACCCHK_NOOVERRIDE;
3075 override = NFSACCCHK_ALLOWOWNER;
3076 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
3077 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
3078 exp, p, override, NFSACCCHK_VPISLOCKED, NULL);
3079 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
3080 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
3081 exp, p, override, NFSACCCHK_VPISLOCKED, NULL);
3083 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
3084 nd->nd_cred, exp, p, override,
3085 NFSACCCHK_VPISLOCKED, NULL);
3088 if (!nd->nd_repstat) {
3089 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
3090 if (!nd->nd_repstat) {
3091 tverf[0] = nva.na_atime.tv_sec;
3092 tverf[1] = nva.na_atime.tv_nsec;
3095 if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
3096 cverf[1] != tverf[1]))
3097 nd->nd_repstat = EEXIST;
3099 * Do the open locking/delegation stuff.
3101 if (!nd->nd_repstat)
3102 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
3103 &delegstateid, &rflags, exp, p, nva.na_filerev);
3106 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
3107 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
3108 * (ie: Leave the NFSVOPUNLOCK() about here.)
3113 free(stp, M_NFSDSTATE);
3114 if (!nd->nd_repstat && dirp)
3115 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
3116 if (!nd->nd_repstat) {
3117 /* For NFSv4.1, set the Current StateID. */
3118 if ((nd->nd_flag & ND_NFSV41) != 0) {
3119 nd->nd_curstateid = stateid;
3120 nd->nd_flag |= ND_CURSTATEID;
3122 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
3123 *tl++ = txdr_unsigned(stateid.seqid);
3124 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3125 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3126 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
3127 *tl++ = newnfs_true;
3133 *tl++ = newnfs_false; /* Since dirp is not locked */
3134 txdr_hyper(dirfor.na_filerev, tl);
3136 txdr_hyper(diraft.na_filerev, tl);
3139 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
3140 (void) nfsrv_putattrbit(nd, &attrbits);
3141 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3142 if (rflags & NFSV4OPEN_READDELEGATE)
3143 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
3144 else if (rflags & NFSV4OPEN_WRITEDELEGATE)
3145 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
3146 else if (retext != 0) {
3147 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT);
3148 if ((rflags & NFSV4OPEN_WDNOTWANTED) != 0) {
3149 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3150 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
3151 } else if ((rflags & NFSV4OPEN_WDSUPPFTYPE) != 0) {
3152 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3153 *tl = txdr_unsigned(NFSV4OPEN_NOTSUPPFTYPE);
3154 } else if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) {
3155 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3156 *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION);
3158 } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) {
3159 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3160 *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE);
3163 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3164 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
3167 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
3168 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
3169 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
3170 *tl++ = txdr_unsigned(delegstateid.seqid);
3171 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
3173 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3174 if (rflags & NFSV4OPEN_RECALL)
3178 if (rflags & NFSV4OPEN_WRITEDELEGATE) {
3179 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3180 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
3181 txdr_hyper(nva.na_size, tl);
3183 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3184 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
3185 *tl++ = txdr_unsigned(0x0);
3186 acemask = NFSV4ACE_ALLFILESMASK;
3187 if (nva.na_mode & S_IRUSR)
3188 acemask |= NFSV4ACE_READMASK;
3189 if (nva.na_mode & S_IWUSR)
3190 acemask |= NFSV4ACE_WRITEMASK;
3191 if (nva.na_mode & S_IXUSR)
3192 acemask |= NFSV4ACE_EXECUTEMASK;
3193 *tl = txdr_unsigned(acemask);
3194 (void) nfsm_strtom(nd, "OWNER@", 6);
3202 #ifdef NFS4_ACL_EXTATTR_NAME
3205 NFSEXITCODE2(0, nd);
3209 #ifdef NFS4_ACL_EXTATTR_NAME
3213 free(stp, M_NFSDSTATE);
3214 NFSEXITCODE2(error, nd);
3219 * nfsv4 close service
3222 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
3223 vnode_t vp, __unused struct nfsexstuff *exp)
3226 struct nfsstate st, *stp = &st;
3227 int error = 0, writeacc;
3228 nfsv4stateid_t stateid;
3231 struct thread *p = curthread;
3233 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
3234 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3235 stp->ls_ownerlen = 0;
3236 stp->ls_op = nd->nd_rp;
3237 stp->ls_uid = nd->nd_cred->cr_uid;
3238 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3239 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3243 * For the special stateid of other all 0s and seqid == 1, set the
3244 * stateid to the current stateid, if it is set.
3246 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
3247 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
3248 stp->ls_stateid.other[2] == 0) {
3249 if ((nd->nd_flag & ND_CURSTATEID) != 0)
3250 stp->ls_stateid = nd->nd_curstateid;
3252 nd->nd_repstat = NFSERR_BADSTATEID;
3257 stp->ls_flags = NFSLCK_CLOSE;
3258 clientid.lval[0] = stp->ls_stateid.other[0];
3259 clientid.lval[1] = stp->ls_stateid.other[1];
3260 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3261 if ((nd->nd_flag & ND_NFSV41) != 0)
3262 clientid.qval = nd->nd_clientid.qval;
3263 else if (nd->nd_clientid.qval != clientid.qval)
3264 printf("EEK8 multiple clids\n");
3266 if ((nd->nd_flag & ND_NFSV41) != 0)
3267 printf("EEK! no clientid from session\n");
3268 nd->nd_flag |= ND_IMPLIEDCLID;
3269 nd->nd_clientid.qval = clientid.qval;
3271 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
3273 /* For pNFS, update the attributes. */
3274 if (writeacc != 0 || nfsrv_pnfsatime != 0)
3275 nfsrv_updatemdsattr(vp, &na, p);
3277 if (!nd->nd_repstat) {
3279 * If the stateid that has been closed is the current stateid,
3282 if ((nd->nd_flag & ND_CURSTATEID) != 0 &&
3283 stateid.other[0] == nd->nd_curstateid.other[0] &&
3284 stateid.other[1] == nd->nd_curstateid.other[1] &&
3285 stateid.other[2] == nd->nd_curstateid.other[2])
3286 nd->nd_flag &= ~ND_CURSTATEID;
3287 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3288 *tl++ = txdr_unsigned(stateid.seqid);
3289 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3291 NFSEXITCODE2(0, nd);
3295 NFSEXITCODE2(error, nd);
3300 * nfsv4 delegpurge service
3303 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
3304 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3309 struct thread *p = curthread;
3311 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3312 nd->nd_repstat = NFSERR_WRONGSEC;
3315 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3316 clientid.lval[0] = *tl++;
3317 clientid.lval[1] = *tl;
3318 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3319 if ((nd->nd_flag & ND_NFSV41) != 0)
3320 clientid.qval = nd->nd_clientid.qval;
3321 else if (nd->nd_clientid.qval != clientid.qval)
3322 printf("EEK9 multiple clids\n");
3324 if ((nd->nd_flag & ND_NFSV41) != 0)
3325 printf("EEK! no clientid from session\n");
3326 nd->nd_flag |= ND_IMPLIEDCLID;
3327 nd->nd_clientid.qval = clientid.qval;
3329 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL,
3330 NFSV4OP_DELEGPURGE, nd->nd_cred, p, NULL);
3332 NFSEXITCODE2(error, nd);
3337 * nfsv4 delegreturn service
3340 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
3341 vnode_t vp, __unused struct nfsexstuff *exp)
3344 int error = 0, writeacc;
3345 nfsv4stateid_t stateid;
3348 struct thread *p = curthread;
3350 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3351 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3352 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
3353 clientid.lval[0] = stateid.other[0];
3354 clientid.lval[1] = stateid.other[1];
3355 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3356 if ((nd->nd_flag & ND_NFSV41) != 0)
3357 clientid.qval = nd->nd_clientid.qval;
3358 else if (nd->nd_clientid.qval != clientid.qval)
3359 printf("EEK10 multiple clids\n");
3361 if ((nd->nd_flag & ND_NFSV41) != 0)
3362 printf("EEK! no clientid from session\n");
3363 nd->nd_flag |= ND_IMPLIEDCLID;
3364 nd->nd_clientid.qval = clientid.qval;
3366 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp,
3367 NFSV4OP_DELEGRETURN, nd->nd_cred, p, &writeacc);
3368 /* For pNFS, update the attributes. */
3369 if (writeacc != 0 || nfsrv_pnfsatime != 0)
3370 nfsrv_updatemdsattr(vp, &na, p);
3373 NFSEXITCODE2(error, nd);
3378 * nfsv4 get file handle service
3381 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
3382 vnode_t vp, __unused struct nfsexstuff *exp)
3385 struct thread *p = curthread;
3387 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3389 if (!nd->nd_repstat)
3390 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
3391 NFSEXITCODE2(0, nd);
3396 * nfsv4 open confirm service
3399 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
3400 vnode_t vp, __unused struct nfsexstuff *exp)
3403 struct nfsstate st, *stp = &st;
3405 nfsv4stateid_t stateid;
3407 struct thread *p = curthread;
3409 if ((nd->nd_flag & ND_NFSV41) != 0) {
3410 nd->nd_repstat = NFSERR_NOTSUPP;
3413 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
3414 stp->ls_ownerlen = 0;
3415 stp->ls_op = nd->nd_rp;
3416 stp->ls_uid = nd->nd_cred->cr_uid;
3417 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3418 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3420 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3421 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
3422 stp->ls_flags = NFSLCK_CONFIRM;
3423 clientid.lval[0] = stp->ls_stateid.other[0];
3424 clientid.lval[1] = stp->ls_stateid.other[1];
3425 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3426 if ((nd->nd_flag & ND_NFSV41) != 0)
3427 clientid.qval = nd->nd_clientid.qval;
3428 else if (nd->nd_clientid.qval != clientid.qval)
3429 printf("EEK11 multiple clids\n");
3431 if ((nd->nd_flag & ND_NFSV41) != 0)
3432 printf("EEK! no clientid from session\n");
3433 nd->nd_flag |= ND_IMPLIEDCLID;
3434 nd->nd_clientid.qval = clientid.qval;
3436 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
3438 if (!nd->nd_repstat) {
3439 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3440 *tl++ = txdr_unsigned(stateid.seqid);
3441 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3445 NFSEXITCODE2(error, nd);
3450 * nfsv4 open downgrade service
3453 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
3454 vnode_t vp, __unused struct nfsexstuff *exp)
3458 struct nfsstate st, *stp = &st;
3460 nfsv4stateid_t stateid;
3462 struct thread *p = curthread;
3464 /* opendowngrade can only work on a file object.*/
3465 if (vp->v_type != VREG) {
3466 error = NFSERR_INVAL;
3469 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
3470 stp->ls_ownerlen = 0;
3471 stp->ls_op = nd->nd_rp;
3472 stp->ls_uid = nd->nd_cred->cr_uid;
3473 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3474 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3476 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3479 * For the special stateid of other all 0s and seqid == 1, set the
3480 * stateid to the current stateid, if it is set.
3482 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
3483 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
3484 stp->ls_stateid.other[2] == 0) {
3485 if ((nd->nd_flag & ND_CURSTATEID) != 0)
3486 stp->ls_stateid = nd->nd_curstateid;
3488 nd->nd_repstat = NFSERR_BADSTATEID;
3493 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3494 i = fxdr_unsigned(int, *tl++);
3495 if ((nd->nd_flag & ND_NFSV41) != 0)
3496 i &= ~NFSV4OPEN_WANTDELEGMASK;
3498 case NFSV4OPEN_ACCESSREAD:
3499 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
3501 case NFSV4OPEN_ACCESSWRITE:
3502 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
3504 case NFSV4OPEN_ACCESSBOTH:
3505 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
3509 nd->nd_repstat = NFSERR_INVAL;
3511 i = fxdr_unsigned(int, *tl);
3513 case NFSV4OPEN_DENYNONE:
3515 case NFSV4OPEN_DENYREAD:
3516 stp->ls_flags |= NFSLCK_READDENY;
3518 case NFSV4OPEN_DENYWRITE:
3519 stp->ls_flags |= NFSLCK_WRITEDENY;
3521 case NFSV4OPEN_DENYBOTH:
3522 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3525 nd->nd_repstat = NFSERR_INVAL;
3528 clientid.lval[0] = stp->ls_stateid.other[0];
3529 clientid.lval[1] = stp->ls_stateid.other[1];
3530 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3531 if ((nd->nd_flag & ND_NFSV41) != 0)
3532 clientid.qval = nd->nd_clientid.qval;
3533 else if (nd->nd_clientid.qval != clientid.qval)
3534 printf("EEK12 multiple clids\n");
3536 if ((nd->nd_flag & ND_NFSV41) != 0)
3537 printf("EEK! no clientid from session\n");
3538 nd->nd_flag |= ND_IMPLIEDCLID;
3539 nd->nd_clientid.qval = clientid.qval;
3541 if (!nd->nd_repstat)
3542 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3544 if (!nd->nd_repstat) {
3545 /* For NFSv4.1, set the Current StateID. */
3546 if ((nd->nd_flag & ND_NFSV41) != 0) {
3547 nd->nd_curstateid = stateid;
3548 nd->nd_flag |= ND_CURSTATEID;
3550 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3551 *tl++ = txdr_unsigned(stateid.seqid);
3552 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3556 NFSEXITCODE2(error, nd);
3561 * nfsv4 renew lease service
3564 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3565 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3570 struct thread *p = curthread;
3572 if ((nd->nd_flag & ND_NFSV41) != 0) {
3573 nd->nd_repstat = NFSERR_NOTSUPP;
3576 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3577 nd->nd_repstat = NFSERR_WRONGSEC;
3580 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3581 clientid.lval[0] = *tl++;
3582 clientid.lval[1] = *tl;
3583 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3584 if ((nd->nd_flag & ND_NFSV41) != 0)
3585 clientid.qval = nd->nd_clientid.qval;
3586 else if (nd->nd_clientid.qval != clientid.qval)
3587 printf("EEK13 multiple clids\n");
3589 if ((nd->nd_flag & ND_NFSV41) != 0)
3590 printf("EEK! no clientid from session\n");
3591 nd->nd_flag |= ND_IMPLIEDCLID;
3592 nd->nd_clientid.qval = clientid.qval;
3594 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3595 NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p);
3597 NFSEXITCODE2(error, nd);
3602 * nfsv4 security info service
3605 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3606 vnode_t dp, struct nfsexstuff *exp)
3610 struct nameidata named;
3611 vnode_t dirp = NULL, vp;
3613 struct nfsexstuff retnes;
3615 int error = 0, savflag, i;
3618 struct thread *p = curthread;
3621 * All this just to get the export flags for the name.
3623 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3624 LOCKLEAF | SAVESTART);
3625 nfsvno_setpathbuf(&named, &bufp, &hashp);
3626 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3629 nfsvno_relpathbuf(&named);
3632 if (!nd->nd_repstat) {
3633 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
3636 nfsvno_relpathbuf(&named);
3642 vrele(named.ni_startdir);
3643 nfsvno_relpathbuf(&named);
3644 fh.nfsrvfh_len = NFSX_MYFH;
3646 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3648 savflag = nd->nd_flag;
3649 if (!nd->nd_repstat) {
3650 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0);
3654 nd->nd_flag = savflag;
3659 * Finally have the export flags for name, so we can create
3660 * the security info.
3663 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3664 for (i = 0; i < retnes.nes_numsecflavor; i++) {
3665 if (retnes.nes_secflavors[i] == AUTH_SYS) {
3666 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3667 *tl = txdr_unsigned(RPCAUTH_UNIX);
3669 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3670 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3671 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3672 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3673 nfsgss_mechlist[KERBV_MECH].len);
3674 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3675 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3676 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3678 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3679 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3680 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3681 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3682 nfsgss_mechlist[KERBV_MECH].len);
3683 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3684 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3685 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3687 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3688 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3689 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3690 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3691 nfsgss_mechlist[KERBV_MECH].len);
3692 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3693 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3694 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3698 *sizp = txdr_unsigned(len);
3701 NFSEXITCODE2(error, nd);
3706 * nfsv4 set client id service
3709 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3710 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3714 int error = 0, idlen;
3715 struct nfsclient *clp = NULL;
3717 struct sockaddr_in *rin;
3720 struct sockaddr_in6 *rin6;
3722 #if defined(INET) || defined(INET6)
3725 u_char *verf, *addrbuf;
3726 nfsquad_t clientid, confirm;
3727 struct thread *p = curthread;
3729 if ((nd->nd_flag & ND_NFSV41) != 0) {
3730 nd->nd_repstat = NFSERR_NOTSUPP;
3733 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3734 nd->nd_repstat = NFSERR_WRONGSEC;
3737 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3738 verf = (u_char *)tl;
3739 tl += (NFSX_VERF / NFSX_UNSIGNED);
3740 i = fxdr_unsigned(int, *tl);
3741 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3742 nd->nd_repstat = NFSERR_BADXDR;
3746 if (nd->nd_flag & ND_GSS)
3747 i += nd->nd_princlen;
3748 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
3750 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
3751 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
3752 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3753 /* Allocated large enough for an AF_INET or AF_INET6 socket. */
3754 clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
3756 clp->lc_req.nr_cred = NULL;
3757 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3758 clp->lc_idlen = idlen;
3759 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3762 if (nd->nd_flag & ND_GSS) {
3763 clp->lc_flags = LCL_GSS;
3764 if (nd->nd_flag & ND_GSSINTEGRITY)
3765 clp->lc_flags |= LCL_GSSINTEGRITY;
3766 else if (nd->nd_flag & ND_GSSPRIVACY)
3767 clp->lc_flags |= LCL_GSSPRIVACY;
3771 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
3772 clp->lc_flags |= LCL_NAME;
3773 clp->lc_namelen = nd->nd_princlen;
3774 clp->lc_name = &clp->lc_id[idlen];
3775 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3777 clp->lc_uid = nd->nd_cred->cr_uid;
3778 clp->lc_gid = nd->nd_cred->cr_gid;
3780 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3781 clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
3782 error = nfsrv_getclientipaddr(nd, clp);
3785 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3786 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
3789 * nfsrv_setclient() does the actual work of adding it to the
3790 * client list. If there is no error, the structure has been
3791 * linked into the client list and clp should no longer be used
3792 * here. When an error is returned, it has not been linked in,
3793 * so it should be free'd.
3795 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3796 if (nd->nd_repstat == NFSERR_CLIDINUSE) {
3798 * 8 is the maximum length of the port# string.
3800 addrbuf = malloc(INET6_ADDRSTRLEN + 8, M_TEMP, M_WAITOK);
3801 switch (clp->lc_req.nr_nam->sa_family) {
3804 if (clp->lc_flags & LCL_TCPCALLBACK)
3805 (void) nfsm_strtom(nd, "tcp", 3);
3807 (void) nfsm_strtom(nd, "udp", 3);
3808 rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
3809 ucp = (u_char *)&rin->sin_addr.s_addr;
3810 ucp2 = (u_char *)&rin->sin_port;
3811 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
3812 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
3813 ucp2[0] & 0xff, ucp2[1] & 0xff);
3818 if (clp->lc_flags & LCL_TCPCALLBACK)
3819 (void) nfsm_strtom(nd, "tcp6", 4);
3821 (void) nfsm_strtom(nd, "udp6", 4);
3822 rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
3823 ucp = inet_ntop(AF_INET6, &rin6->sin6_addr, addrbuf,
3829 ucp2 = (u_char *)&rin6->sin6_port;
3830 sprintf(&addrbuf[i], ".%d.%d", ucp2[0] & 0xff,
3835 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
3836 free(addrbuf, M_TEMP);
3839 free(clp->lc_req.nr_nam, M_SONAME);
3840 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3841 free(clp->lc_stateid, M_NFSDCLIENT);
3842 free(clp, M_NFSDCLIENT);
3844 if (!nd->nd_repstat) {
3845 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
3846 *tl++ = clientid.lval[0];
3847 *tl++ = clientid.lval[1];
3848 *tl++ = confirm.lval[0];
3849 *tl = confirm.lval[1];
3853 NFSEXITCODE2(0, nd);
3857 free(clp->lc_req.nr_nam, M_SONAME);
3858 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3859 free(clp->lc_stateid, M_NFSDCLIENT);
3860 free(clp, M_NFSDCLIENT);
3862 NFSEXITCODE2(error, nd);
3867 * nfsv4 set client id confirm service
3870 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
3871 __unused int isdgram, __unused vnode_t vp,
3872 __unused struct nfsexstuff *exp)
3876 nfsquad_t clientid, confirm;
3877 struct thread *p = curthread;
3879 if ((nd->nd_flag & ND_NFSV41) != 0) {
3880 nd->nd_repstat = NFSERR_NOTSUPP;
3883 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3884 nd->nd_repstat = NFSERR_WRONGSEC;
3887 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
3888 clientid.lval[0] = *tl++;
3889 clientid.lval[1] = *tl++;
3890 confirm.lval[0] = *tl++;
3891 confirm.lval[1] = *tl;
3894 * nfsrv_getclient() searches the client list for a match and
3895 * returns the appropriate NFSERR status.
3897 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
3898 NULL, NULL, confirm, 0, nd, p);
3900 NFSEXITCODE2(error, nd);
3905 * nfsv4 verify service
3908 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
3909 vnode_t vp, __unused struct nfsexstuff *exp)
3911 int error = 0, ret, fhsize = NFSX_MYFH;
3912 struct nfsvattr nva;
3914 struct nfsfsinfo fs;
3916 struct thread *p = curthread;
3918 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
3919 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
3920 if (!nd->nd_repstat)
3921 nd->nd_repstat = nfsvno_statfs(vp, sf);
3922 if (!nd->nd_repstat)
3923 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3924 if (!nd->nd_repstat) {
3925 nfsvno_getfs(&fs, isdgram);
3926 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
3927 sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
3929 if (nd->nd_procnum == NFSV4OP_NVERIFY) {
3931 nd->nd_repstat = NFSERR_SAME;
3932 else if (ret != NFSERR_NOTSAME)
3933 nd->nd_repstat = ret;
3935 nd->nd_repstat = ret;
3940 NFSEXITCODE2(error, nd);
3948 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
3949 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
3950 __unused struct nfsexstuff *exp)
3953 int error = 0, createdir __unused;
3955 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3956 createdir = fxdr_unsigned(int, *tl);
3957 nd->nd_repstat = NFSERR_NOTSUPP;
3960 NFSEXITCODE2(error, nd);
3965 * nfsv4 release lock owner service
3968 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
3969 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3972 struct nfsstate *stp = NULL;
3975 struct thread *p = curthread;
3977 if ((nd->nd_flag & ND_NFSV41) != 0) {
3978 nd->nd_repstat = NFSERR_NOTSUPP;
3981 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3982 nd->nd_repstat = NFSERR_WRONGSEC;
3985 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3986 len = fxdr_unsigned(int, *(tl + 2));
3987 if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
3988 nd->nd_repstat = NFSERR_BADXDR;
3991 stp = malloc(sizeof (struct nfsstate) + len,
3992 M_NFSDSTATE, M_WAITOK);
3993 stp->ls_ownerlen = len;
3995 stp->ls_flags = NFSLCK_RELEASE;
3996 stp->ls_uid = nd->nd_cred->cr_uid;
3997 clientid.lval[0] = *tl++;
3998 clientid.lval[1] = *tl;
3999 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
4000 if ((nd->nd_flag & ND_NFSV41) != 0)
4001 clientid.qval = nd->nd_clientid.qval;
4002 else if (nd->nd_clientid.qval != clientid.qval)
4003 printf("EEK14 multiple clids\n");
4005 if ((nd->nd_flag & ND_NFSV41) != 0)
4006 printf("EEK! no clientid from session\n");
4007 nd->nd_flag |= ND_IMPLIEDCLID;
4008 nd->nd_clientid.qval = clientid.qval;
4010 error = nfsrv_mtostr(nd, stp->ls_owner, len);
4013 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
4014 free(stp, M_NFSDSTATE);
4016 NFSEXITCODE2(0, nd);
4020 free(stp, M_NFSDSTATE);
4021 NFSEXITCODE2(error, nd);
4026 * nfsv4 exchange_id service
4029 nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram,
4030 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4033 int error = 0, i, idlen;
4034 struct nfsclient *clp = NULL;
4035 nfsquad_t clientid, confirm;
4037 uint32_t sp4type, v41flags;
4038 uint64_t owner_minor;
4039 struct timespec verstime;
4041 struct sockaddr_in *sin, *rin;
4044 struct sockaddr_in6 *sin6, *rin6;
4046 struct thread *p = curthread;
4048 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4049 nd->nd_repstat = NFSERR_WRONGSEC;
4052 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
4053 verf = (uint8_t *)tl;
4054 tl += (NFSX_VERF / NFSX_UNSIGNED);
4055 i = fxdr_unsigned(int, *tl);
4056 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
4057 nd->nd_repstat = NFSERR_BADXDR;
4061 if (nd->nd_flag & ND_GSS)
4062 i += nd->nd_princlen;
4063 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
4065 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
4066 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
4067 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
4068 /* Allocated large enough for an AF_INET or AF_INET6 socket. */
4069 clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
4071 switch (nd->nd_nam->sa_family) {
4074 rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
4075 sin = (struct sockaddr_in *)nd->nd_nam;
4076 rin->sin_family = AF_INET;
4077 rin->sin_len = sizeof(struct sockaddr_in);
4079 rin->sin_addr.s_addr = sin->sin_addr.s_addr;
4084 rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
4085 sin6 = (struct sockaddr_in6 *)nd->nd_nam;
4086 rin6->sin6_family = AF_INET6;
4087 rin6->sin6_len = sizeof(struct sockaddr_in6);
4088 rin6->sin6_port = 0;
4089 rin6->sin6_addr = sin6->sin6_addr;
4093 clp->lc_req.nr_cred = NULL;
4094 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
4095 clp->lc_idlen = idlen;
4096 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
4099 if ((nd->nd_flag & ND_GSS) != 0) {
4100 clp->lc_flags = LCL_GSS | LCL_NFSV41;
4101 if ((nd->nd_flag & ND_GSSINTEGRITY) != 0)
4102 clp->lc_flags |= LCL_GSSINTEGRITY;
4103 else if ((nd->nd_flag & ND_GSSPRIVACY) != 0)
4104 clp->lc_flags |= LCL_GSSPRIVACY;
4106 clp->lc_flags = LCL_NFSV41;
4107 if ((nd->nd_flag & ND_NFSV42) != 0)
4108 clp->lc_flags |= LCL_NFSV42;
4109 if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) {
4110 clp->lc_flags |= LCL_NAME;
4111 clp->lc_namelen = nd->nd_princlen;
4112 clp->lc_name = &clp->lc_id[idlen];
4113 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
4115 clp->lc_uid = nd->nd_cred->cr_uid;
4116 clp->lc_gid = nd->nd_cred->cr_gid;
4118 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4119 v41flags = fxdr_unsigned(uint32_t, *tl++);
4120 if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR |
4121 NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS |
4122 NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) {
4123 nd->nd_repstat = NFSERR_INVAL;
4126 if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0)
4127 confirm.lval[1] = 1;
4129 confirm.lval[1] = 0;
4130 if (nfsrv_devidcnt == 0)
4131 v41flags = NFSV4EXCH_USENONPNFS | NFSV4EXCH_USEPNFSDS;
4133 v41flags = NFSV4EXCH_USEPNFSMDS;
4134 sp4type = fxdr_unsigned(uint32_t, *tl);
4135 if (sp4type != NFSV4EXCH_SP4NONE) {
4136 nd->nd_repstat = NFSERR_NOTSUPP;
4141 * nfsrv_setclient() does the actual work of adding it to the
4142 * client list. If there is no error, the structure has been
4143 * linked into the client list and clp should no longer be used
4144 * here. When an error is returned, it has not been linked in,
4145 * so it should be free'd.
4147 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
4149 free(clp->lc_req.nr_nam, M_SONAME);
4150 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4151 free(clp->lc_stateid, M_NFSDCLIENT);
4152 free(clp, M_NFSDCLIENT);
4154 if (nd->nd_repstat == 0) {
4155 if (confirm.lval[1] != 0)
4156 v41flags |= NFSV4EXCH_CONFIRMEDR;
4157 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED);
4158 *tl++ = clientid.lval[0]; /* ClientID */
4159 *tl++ = clientid.lval[1];
4160 *tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */
4161 *tl++ = txdr_unsigned(v41flags); /* Exch flags */
4162 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); /* No SSV */
4163 owner_minor = 0; /* Owner */
4164 txdr_hyper(owner_minor, tl); /* Minor */
4165 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid,
4166 strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */
4167 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid,
4168 strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Scope */
4169 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4170 *tl = txdr_unsigned(1);
4171 (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
4172 (void)nfsm_strtom(nd, version, strlen(version));
4173 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
4174 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */
4175 verstime.tv_nsec = 0;
4176 txdr_nfsv4time(&verstime, tl);
4178 NFSEXITCODE2(0, nd);
4182 free(clp->lc_req.nr_nam, M_SONAME);
4183 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4184 free(clp->lc_stateid, M_NFSDCLIENT);
4185 free(clp, M_NFSDCLIENT);
4187 NFSEXITCODE2(error, nd);
4192 * nfsv4 create session service
4195 nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram,
4196 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4200 nfsquad_t clientid, confirm;
4201 struct nfsdsession *sep = NULL;
4203 struct thread *p = curthread;
4205 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4206 nd->nd_repstat = NFSERR_WRONGSEC;
4209 sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession),
4210 M_NFSDSESSION, M_WAITOK | M_ZERO);
4211 sep->sess_refcnt = 1;
4212 mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF);
4213 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
4214 clientid.lval[0] = *tl++;
4215 clientid.lval[1] = *tl++;
4216 confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++);
4217 sep->sess_crflags = fxdr_unsigned(uint32_t, *tl);
4218 /* Persistent sessions and RDMA are not supported. */
4219 sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN;
4221 /* Fore channel attributes. */
4222 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4223 tl++; /* Header pad always 0. */
4224 sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++);
4225 if (sep->sess_maxreq > sb_max_adj - NFS_MAXXDR) {
4226 sep->sess_maxreq = sb_max_adj - NFS_MAXXDR;
4227 printf("Consider increasing kern.ipc.maxsockbuf\n");
4229 sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++);
4230 if (sep->sess_maxresp > sb_max_adj - NFS_MAXXDR) {
4231 sep->sess_maxresp = sb_max_adj - NFS_MAXXDR;
4232 printf("Consider increasing kern.ipc.maxsockbuf\n");
4234 sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++);
4235 sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++);
4236 sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++);
4237 if (sep->sess_maxslots > NFSV4_SLOTS)
4238 sep->sess_maxslots = NFSV4_SLOTS;
4239 rdmacnt = fxdr_unsigned(uint32_t, *tl);
4241 nd->nd_repstat = NFSERR_BADXDR;
4243 } else if (rdmacnt == 1)
4244 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4246 /* Back channel attributes. */
4247 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4248 tl++; /* Header pad always 0. */
4249 sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++);
4250 sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++);
4251 sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++);
4252 sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++);
4253 sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++);
4254 rdmacnt = fxdr_unsigned(uint32_t, *tl);
4256 nd->nd_repstat = NFSERR_BADXDR;
4258 } else if (rdmacnt == 1)
4259 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4261 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4262 sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl);
4265 * nfsrv_getclient() searches the client list for a match and
4266 * returns the appropriate NFSERR status.
4268 nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW,
4269 NULL, sep, confirm, sep->sess_cbprogram, nd, p);
4270 if (nd->nd_repstat == 0) {
4271 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4272 NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID);
4273 NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED);
4274 *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */
4275 *tl++ = txdr_unsigned(sep->sess_crflags);
4277 /* Fore channel attributes. */
4279 *tl++ = txdr_unsigned(sep->sess_maxreq);
4280 *tl++ = txdr_unsigned(sep->sess_maxresp);
4281 *tl++ = txdr_unsigned(sep->sess_maxrespcached);
4282 *tl++ = txdr_unsigned(sep->sess_maxops);
4283 *tl++ = txdr_unsigned(sep->sess_maxslots);
4284 *tl++ = txdr_unsigned(1);
4285 *tl++ = txdr_unsigned(0); /* No RDMA. */
4287 /* Back channel attributes. */
4289 *tl++ = txdr_unsigned(sep->sess_cbmaxreq);
4290 *tl++ = txdr_unsigned(sep->sess_cbmaxresp);
4291 *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached);
4292 *tl++ = txdr_unsigned(sep->sess_cbmaxops);
4293 *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots);
4294 *tl++ = txdr_unsigned(1);
4295 *tl = txdr_unsigned(0); /* No RDMA. */
4298 if (nd->nd_repstat != 0 && sep != NULL)
4299 free(sep, M_NFSDSESSION);
4300 NFSEXITCODE2(error, nd);
4305 * nfsv4 sequence service
4308 nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram,
4309 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4312 uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid;
4313 int cache_this, error = 0;
4314 struct thread *p = curthread;
4316 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4317 nd->nd_repstat = NFSERR_WRONGSEC;
4320 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID);
4321 NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID);
4322 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4323 sequenceid = fxdr_unsigned(uint32_t, *tl++);
4324 nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++);
4325 highest_slotid = fxdr_unsigned(uint32_t, *tl++);
4326 if (*tl == newnfs_true)
4330 nd->nd_flag |= ND_HASSEQUENCE;
4331 nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid,
4332 &target_highest_slotid, cache_this, &sflags, p);
4333 if (nd->nd_repstat == 0) {
4334 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4335 NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID);
4336 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
4337 *tl++ = txdr_unsigned(sequenceid);
4338 *tl++ = txdr_unsigned(nd->nd_slotid);
4339 *tl++ = txdr_unsigned(highest_slotid);
4340 *tl++ = txdr_unsigned(target_highest_slotid);
4341 *tl = txdr_unsigned(sflags);
4344 NFSEXITCODE2(error, nd);
4349 * nfsv4 reclaim complete service
4352 nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram,
4353 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4356 int error = 0, onefs;
4358 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4359 nd->nd_repstat = NFSERR_WRONGSEC;
4362 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4364 * I believe that a ReclaimComplete with rca_one_fs == TRUE is only
4365 * to be used after a file system has been transferred to a different
4366 * file server. However, RFC5661 is somewhat vague w.r.t. this and
4367 * the ESXi 6.7 client does both a ReclaimComplete with rca_one_fs
4368 * == TRUE and one with ReclaimComplete with rca_one_fs == FALSE.
4369 * Therefore, just ignore the rca_one_fs == TRUE operation and return
4370 * NFS_OK without doing anything.
4373 if (*tl == newnfs_true)
4375 nd->nd_repstat = nfsrv_checkreclaimcomplete(nd, onefs);
4377 NFSEXITCODE2(error, nd);
4382 * nfsv4 destroy clientid service
4385 nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram,
4386 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4391 struct thread *p = curthread;
4393 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4394 nd->nd_repstat = NFSERR_WRONGSEC;
4397 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4398 clientid.lval[0] = *tl++;
4399 clientid.lval[1] = *tl;
4400 nd->nd_repstat = nfsrv_destroyclient(clientid, p);
4402 NFSEXITCODE2(error, nd);
4407 * nfsv4 bind connection to session service
4410 nfsrvd_bindconnsess(struct nfsrv_descript *nd, __unused int isdgram,
4411 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4414 uint8_t sessid[NFSX_V4SESSIONID];
4415 int error = 0, foreaft;
4417 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4418 nd->nd_repstat = NFSERR_WRONGSEC;
4421 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED);
4422 NFSBCOPY(tl, sessid, NFSX_V4SESSIONID);
4423 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
4424 foreaft = fxdr_unsigned(int, *tl++);
4425 if (*tl == newnfs_true) {
4426 /* RDMA is not supported. */
4427 nd->nd_repstat = NFSERR_NOTSUPP;
4431 nd->nd_repstat = nfsrv_bindconnsess(nd, sessid, &foreaft);
4432 if (nd->nd_repstat == 0) {
4433 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 *
4435 NFSBCOPY(sessid, tl, NFSX_V4SESSIONID);
4436 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
4437 *tl++ = txdr_unsigned(foreaft);
4441 NFSEXITCODE2(error, nd);
4446 * nfsv4 destroy session service
4449 nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram,
4450 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4452 uint8_t *cp, sessid[NFSX_V4SESSIONID];
4455 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4456 nd->nd_repstat = NFSERR_WRONGSEC;
4459 NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID);
4460 NFSBCOPY(cp, sessid, NFSX_V4SESSIONID);
4461 nd->nd_repstat = nfsrv_destroysession(nd, sessid);
4463 NFSEXITCODE2(error, nd);
4468 * nfsv4 free stateid service
4471 nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram,
4472 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4475 nfsv4stateid_t stateid;
4477 struct thread *p = curthread;
4479 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4480 nd->nd_repstat = NFSERR_WRONGSEC;
4483 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
4484 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4485 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4488 * For the special stateid of other all 0s and seqid == 1, set the
4489 * stateid to the current stateid, if it is set.
4491 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4492 stateid.other[1] == 0 && stateid.other[2] == 0) {
4493 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4494 stateid = nd->nd_curstateid;
4497 nd->nd_repstat = NFSERR_BADSTATEID;
4502 nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p);
4504 /* If the current stateid has been free'd, unset it. */
4505 if (nd->nd_repstat == 0 && (nd->nd_flag & ND_CURSTATEID) != 0 &&
4506 stateid.other[0] == nd->nd_curstateid.other[0] &&
4507 stateid.other[1] == nd->nd_curstateid.other[1] &&
4508 stateid.other[2] == nd->nd_curstateid.other[2])
4509 nd->nd_flag &= ~ND_CURSTATEID;
4511 NFSEXITCODE2(error, nd);
4516 * nfsv4 layoutget service
4519 nfsrvd_layoutget(struct nfsrv_descript *nd, __unused int isdgram,
4520 vnode_t vp, struct nfsexstuff *exp)
4523 nfsv4stateid_t stateid;
4524 int error = 0, layoutlen, layouttype, iomode, maxcnt, retonclose;
4525 uint64_t offset, len, minlen;
4527 struct thread *p = curthread;
4529 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4530 nd->nd_repstat = NFSERR_WRONGSEC;
4533 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
4535 tl++; /* Signal layout available. Ignore for now. */
4536 layouttype = fxdr_unsigned(int, *tl++);
4537 iomode = fxdr_unsigned(int, *tl++);
4538 offset = fxdr_hyper(tl); tl += 2;
4539 len = fxdr_hyper(tl); tl += 2;
4540 minlen = fxdr_hyper(tl); tl += 2;
4541 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4542 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4543 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4544 maxcnt = fxdr_unsigned(int, *tl);
4545 NFSD_DEBUG(4, "layoutget ltyp=%d iom=%d off=%ju len=%ju mlen=%ju\n",
4546 layouttype, iomode, (uintmax_t)offset, (uintmax_t)len,
4549 (minlen != UINT64_MAX && offset + minlen < offset) ||
4550 (len != UINT64_MAX && offset + len < offset)) {
4551 nd->nd_repstat = NFSERR_INVAL;
4556 * For the special stateid of other all 0s and seqid == 1, set the
4557 * stateid to the current stateid, if it is set.
4559 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4560 stateid.other[1] == 0 && stateid.other[2] == 0) {
4561 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4562 stateid = nd->nd_curstateid;
4565 nd->nd_repstat = NFSERR_BADSTATEID;
4571 if (layouttype == NFSLAYOUT_NFSV4_1_FILES && nfsrv_maxpnfsmirror == 1)
4572 layp = malloc(NFSX_V4FILELAYOUT, M_TEMP, M_WAITOK);
4573 else if (layouttype == NFSLAYOUT_FLEXFILE)
4574 layp = malloc(NFSX_V4FLEXLAYOUT(nfsrv_maxpnfsmirror), M_TEMP,
4577 nd->nd_repstat = NFSERR_UNKNLAYOUTTYPE;
4579 nd->nd_repstat = nfsrv_layoutget(nd, vp, exp, layouttype,
4580 &iomode, &offset, &len, minlen, &stateid, maxcnt,
4581 &retonclose, &layoutlen, layp, nd->nd_cred, p);
4582 NFSD_DEBUG(4, "nfsrv_layoutget stat=%u layoutlen=%d\n", nd->nd_repstat,
4584 if (nd->nd_repstat == 0) {
4585 /* For NFSv4.1, set the Current StateID. */
4586 if ((nd->nd_flag & ND_NFSV41) != 0) {
4587 nd->nd_curstateid = stateid;
4588 nd->nd_flag |= ND_CURSTATEID;
4590 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_STATEID +
4592 *tl++ = txdr_unsigned(retonclose);
4593 *tl++ = txdr_unsigned(stateid.seqid);
4594 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
4595 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4596 *tl++ = txdr_unsigned(1); /* Only returns one layout. */
4597 txdr_hyper(offset, tl); tl += 2;
4598 txdr_hyper(len, tl); tl += 2;
4599 *tl++ = txdr_unsigned(iomode);
4600 *tl = txdr_unsigned(layouttype);
4601 nfsm_strtom(nd, layp, layoutlen);
4602 } else if (nd->nd_repstat == NFSERR_LAYOUTTRYLATER) {
4603 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4609 NFSEXITCODE2(error, nd);
4614 * nfsv4 layoutcommit service
4617 nfsrvd_layoutcommit(struct nfsrv_descript *nd, __unused int isdgram,
4618 vnode_t vp, struct nfsexstuff *exp)
4621 nfsv4stateid_t stateid;
4622 int error = 0, hasnewoff, hasnewmtime, layouttype, maxcnt, reclaim;
4624 uint64_t offset, len, newoff = 0, newsize;
4625 struct timespec newmtime;
4627 struct thread *p = curthread;
4630 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4631 nd->nd_repstat = NFSERR_WRONGSEC;
4634 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + 2 * NFSX_HYPER +
4636 offset = fxdr_hyper(tl); tl += 2;
4637 len = fxdr_hyper(tl); tl += 2;
4638 reclaim = fxdr_unsigned(int, *tl++);
4639 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4640 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4641 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4643 * For the special stateid of other all 0s and seqid == 1, set the
4644 * stateid to the current stateid, if it is set.
4646 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4647 stateid.other[1] == 0 && stateid.other[2] == 0) {
4648 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4649 stateid = nd->nd_curstateid;
4652 nd->nd_repstat = NFSERR_BADSTATEID;
4657 hasnewoff = fxdr_unsigned(int, *tl);
4658 if (hasnewoff != 0) {
4659 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
4660 newoff = fxdr_hyper(tl); tl += 2;
4662 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4663 hasnewmtime = fxdr_unsigned(int, *tl);
4664 if (hasnewmtime != 0) {
4665 NFSM_DISSECT(tl, uint32_t *, NFSX_V4TIME + 2 * NFSX_UNSIGNED);
4666 fxdr_nfsv4time(tl, &newmtime);
4667 tl += (NFSX_V4TIME / NFSX_UNSIGNED);
4669 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4670 layouttype = fxdr_unsigned(int, *tl++);
4671 maxcnt = fxdr_unsigned(int, *tl);
4673 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
4674 error = nfsrv_mtostr(nd, layp, maxcnt);
4678 nd->nd_repstat = nfsrv_layoutcommit(nd, vp, layouttype, hasnewoff,
4679 newoff, offset, len, hasnewmtime, &newmtime, reclaim, &stateid,
4680 maxcnt, layp, &hasnewsize, &newsize, nd->nd_cred, p);
4681 NFSD_DEBUG(4, "nfsrv_layoutcommit stat=%u\n", nd->nd_repstat);
4682 if (nd->nd_repstat == 0) {
4683 if (hasnewsize != 0) {
4684 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER);
4685 *tl++ = newnfs_true;
4686 txdr_hyper(newsize, tl);
4688 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4695 NFSEXITCODE2(error, nd);
4700 * nfsv4 layoutreturn service
4703 nfsrvd_layoutreturn(struct nfsrv_descript *nd, __unused int isdgram,
4704 vnode_t vp, struct nfsexstuff *exp)
4706 uint32_t *tl, *layp;
4707 nfsv4stateid_t stateid;
4708 int error = 0, fnd, kind, layouttype, iomode, maxcnt, reclaim;
4709 uint64_t offset, len;
4710 struct thread *p = curthread;
4713 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4714 nd->nd_repstat = NFSERR_WRONGSEC;
4717 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4719 layouttype = fxdr_unsigned(int, *tl++);
4720 iomode = fxdr_unsigned(int, *tl++);
4721 kind = fxdr_unsigned(int, *tl);
4722 NFSD_DEBUG(4, "layoutreturn recl=%d ltyp=%d iom=%d kind=%d\n", reclaim,
4723 layouttype, iomode, kind);
4724 if (kind == NFSV4LAYOUTRET_FILE) {
4725 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
4727 offset = fxdr_hyper(tl); tl += 2;
4728 len = fxdr_hyper(tl); tl += 2;
4729 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4730 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4731 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4734 * For the special stateid of other all 0s and seqid == 1, set
4735 * the stateid to the current stateid, if it is set.
4737 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4738 stateid.other[1] == 0 && stateid.other[2] == 0) {
4739 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4740 stateid = nd->nd_curstateid;
4743 nd->nd_repstat = NFSERR_BADSTATEID;
4748 maxcnt = fxdr_unsigned(int, *tl);
4750 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
4751 error = nfsrv_mtostr(nd, (char *)layp, maxcnt);
4756 if (reclaim == newnfs_true) {
4757 nd->nd_repstat = NFSERR_INVAL;
4763 nd->nd_repstat = nfsrv_layoutreturn(nd, vp, layouttype, iomode,
4764 offset, len, reclaim, kind, &stateid, maxcnt, layp, &fnd,
4766 NFSD_DEBUG(4, "nfsrv_layoutreturn stat=%u fnd=%d\n", nd->nd_repstat,
4768 if (nd->nd_repstat == 0) {
4769 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4772 NFSM_BUILD(tl, uint32_t *, NFSX_STATEID);
4773 *tl++ = txdr_unsigned(stateid.seqid);
4774 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
4781 NFSEXITCODE2(error, nd);
4786 * nfsv4 layout error service
4789 nfsrvd_layouterror(struct nfsrv_descript *nd, __unused int isdgram,
4790 vnode_t vp, struct nfsexstuff *exp)
4793 nfsv4stateid_t stateid;
4794 int cnt, error = 0, i, stat;
4796 char devid[NFSX_V4DEVICEID];
4797 uint64_t offset, len;
4799 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4800 nd->nd_repstat = NFSERR_WRONGSEC;
4803 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
4805 offset = fxdr_hyper(tl); tl += 2;
4806 len = fxdr_hyper(tl); tl += 2;
4807 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4808 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4809 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4810 cnt = fxdr_unsigned(int, *tl);
4811 NFSD_DEBUG(4, "layouterror off=%ju len=%ju cnt=%d\n", (uintmax_t)offset,
4812 (uintmax_t)len, cnt);
4814 * For the special stateid of other all 0s and seqid == 1, set
4815 * the stateid to the current stateid, if it is set.
4817 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4818 stateid.other[1] == 0 && stateid.other[2] == 0) {
4819 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4820 stateid = nd->nd_curstateid;
4823 nd->nd_repstat = NFSERR_BADSTATEID;
4829 * Ignore offset, len and stateid for now.
4831 for (i = 0; i < cnt; i++) {
4832 NFSM_DISSECT(tl, uint32_t *, NFSX_V4DEVICEID + 2 *
4834 NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
4835 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
4836 stat = fxdr_unsigned(int, *tl++);
4837 opnum = fxdr_unsigned(int, *tl);
4838 NFSD_DEBUG(4, "nfsrvd_layouterr op=%d stat=%d\n", opnum, stat);
4840 * Except for NFSERR_ACCES and NFSERR_STALE errors,
4841 * disable the mirror.
4843 if (stat != NFSERR_ACCES && stat != NFSERR_STALE)
4844 nfsrv_delds(devid, curthread);
4848 NFSEXITCODE2(error, nd);
4853 * nfsv4 layout stats service
4856 nfsrvd_layoutstats(struct nfsrv_descript *nd, __unused int isdgram,
4857 vnode_t vp, struct nfsexstuff *exp)
4860 nfsv4stateid_t stateid;
4862 int layouttype __unused;
4863 char devid[NFSX_V4DEVICEID] __unused;
4864 uint64_t offset, len, readcount, readbytes, writecount, writebytes
4867 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4868 nd->nd_repstat = NFSERR_WRONGSEC;
4871 NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_HYPER + NFSX_STATEID +
4872 NFSX_V4DEVICEID + 2 * NFSX_UNSIGNED);
4873 offset = fxdr_hyper(tl); tl += 2;
4874 len = fxdr_hyper(tl); tl += 2;
4875 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4876 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4877 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4878 readcount = fxdr_hyper(tl); tl += 2;
4879 readbytes = fxdr_hyper(tl); tl += 2;
4880 writecount = fxdr_hyper(tl); tl += 2;
4881 writebytes = fxdr_hyper(tl); tl += 2;
4882 NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
4883 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
4884 layouttype = fxdr_unsigned(int, *tl++);
4885 cnt = fxdr_unsigned(int, *tl);
4886 error = nfsm_advance(nd, NFSM_RNDUP(cnt), -1);
4889 NFSD_DEBUG(4, "layoutstats cnt=%d\n", cnt);
4891 * For the special stateid of other all 0s and seqid == 1, set
4892 * the stateid to the current stateid, if it is set.
4894 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4895 stateid.other[1] == 0 && stateid.other[2] == 0) {
4896 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4897 stateid = nd->nd_curstateid;
4900 nd->nd_repstat = NFSERR_BADSTATEID;
4906 * No use for the stats for now.
4910 NFSEXITCODE2(error, nd);
4915 * nfsv4 io_advise service
4918 nfsrvd_ioadvise(struct nfsrv_descript *nd, __unused int isdgram,
4919 vnode_t vp, struct nfsexstuff *exp)
4922 nfsv4stateid_t stateid;
4927 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4928 nd->nd_repstat = NFSERR_WRONGSEC;
4931 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
4932 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4933 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4934 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4935 offset = fxdr_hyper(tl); tl += 2;
4936 len = fxdr_hyper(tl);
4937 error = nfsrv_getattrbits(nd, &hints, NULL, NULL);
4941 * For the special stateid of other all 0s and seqid == 1, set
4942 * the stateid to the current stateid, if it is set.
4944 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4945 stateid.other[1] == 0 && stateid.other[2] == 0) {
4946 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4947 stateid = nd->nd_curstateid;
4950 nd->nd_repstat = NFSERR_BADSTATEID;
4956 nd->nd_repstat = NFSERR_INVAL;
4961 if (vp->v_type != VREG) {
4962 if (vp->v_type == VDIR)
4963 nd->nd_repstat = NFSERR_ISDIR;
4965 nd->nd_repstat = NFSERR_WRONGTYPE;
4970 * For now, we can only handle WILLNEED and DONTNEED and don't use
4973 if ((NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED) &&
4974 !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED)) ||
4975 (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED) &&
4976 !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED))) {
4978 if (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED)) {
4979 ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_WILLNEED);
4980 NFSZERO_ATTRBIT(&hints);
4982 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED);
4984 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
4986 ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_DONTNEED);
4987 NFSZERO_ATTRBIT(&hints);
4989 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED);
4991 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
4995 NFSZERO_ATTRBIT(&hints);
4996 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
4999 nfsrv_putattrbit(nd, &hints);
5000 NFSEXITCODE2(error, nd);
5004 NFSEXITCODE2(error, nd);
5009 * nfsv4 getdeviceinfo service
5012 nfsrvd_getdevinfo(struct nfsrv_descript *nd, __unused int isdgram,
5013 __unused vnode_t vp, __unused struct nfsexstuff *exp)
5015 uint32_t *tl, maxcnt, notify[NFSV4_NOTIFYBITMAP];
5016 int cnt, devaddrlen, error = 0, i, layouttype;
5017 char devid[NFSX_V4DEVICEID], *devaddr;
5020 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5021 nd->nd_repstat = NFSERR_WRONGSEC;
5024 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_V4DEVICEID);
5025 NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
5026 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5027 layouttype = fxdr_unsigned(int, *tl++);
5028 maxcnt = fxdr_unsigned(uint32_t, *tl++);
5029 cnt = fxdr_unsigned(int, *tl);
5030 NFSD_DEBUG(4, "getdevinfo ltyp=%d maxcnt=%u bitcnt=%d\n", layouttype,
5032 if (cnt > NFSV4_NOTIFYBITMAP || cnt < 0) {
5033 nd->nd_repstat = NFSERR_INVAL;
5037 NFSM_DISSECT(tl, uint32_t *, cnt * NFSX_UNSIGNED);
5038 for (i = 0; i < cnt; i++)
5039 notify[i] = fxdr_unsigned(uint32_t, *tl++);
5041 for (i = cnt; i < NFSV4_NOTIFYBITMAP; i++)
5045 * Check that the device id is not stale. Device ids are recreated
5046 * each time the nfsd threads are restarted.
5048 NFSBCOPY(devid, &dev_time, sizeof(dev_time));
5049 if (dev_time != nfsdev_time) {
5050 nd->nd_repstat = NFSERR_NOENT;
5054 /* Look for the device id. */
5055 nd->nd_repstat = nfsrv_getdevinfo(devid, layouttype, &maxcnt,
5056 notify, &devaddrlen, &devaddr);
5057 NFSD_DEBUG(4, "nfsrv_getdevinfo stat=%u\n", nd->nd_repstat);
5058 if (nd->nd_repstat == 0) {
5059 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5060 *tl = txdr_unsigned(layouttype);
5061 nfsm_strtom(nd, devaddr, devaddrlen);
5063 for (i = 0; i < NFSV4_NOTIFYBITMAP; i++) {
5067 NFSM_BUILD(tl, uint32_t *, (cnt + 1) * NFSX_UNSIGNED);
5068 *tl++ = txdr_unsigned(cnt);
5069 for (i = 0; i < cnt; i++)
5070 *tl++ = txdr_unsigned(notify[i]);
5071 } else if (nd->nd_repstat == NFSERR_TOOSMALL) {
5072 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5073 *tl = txdr_unsigned(maxcnt);
5076 NFSEXITCODE2(error, nd);
5081 * nfsv4 test stateid service
5084 nfsrvd_teststateid(struct nfsrv_descript *nd, __unused int isdgram,
5085 __unused vnode_t vp, __unused struct nfsexstuff *exp)
5088 nfsv4stateid_t *stateidp = NULL, *tstateidp;
5089 int cnt, error = 0, i, ret;
5090 struct thread *p = curthread;
5092 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5093 nd->nd_repstat = NFSERR_WRONGSEC;
5096 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5097 cnt = fxdr_unsigned(int, *tl);
5098 if (cnt <= 0 || cnt > 1024) {
5099 nd->nd_repstat = NFSERR_BADXDR;
5102 stateidp = mallocarray(cnt, sizeof(nfsv4stateid_t), M_TEMP, M_WAITOK);
5103 tstateidp = stateidp;
5104 for (i = 0; i < cnt; i++) {
5105 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
5106 tstateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
5107 NFSBCOPY(tl, tstateidp->other, NFSX_STATEIDOTHER);
5110 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5111 *tl = txdr_unsigned(cnt);
5112 tstateidp = stateidp;
5113 for (i = 0; i < cnt; i++) {
5114 ret = nfsrv_teststateid(nd, tstateidp, p);
5115 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5116 *tl = txdr_unsigned(ret);
5120 free(stateidp, M_TEMP);
5121 NFSEXITCODE2(error, nd);
5126 * nfs allocate service
5129 nfsrvd_allocate(struct nfsrv_descript *nd, __unused int isdgram,
5130 vnode_t vp, struct nfsexstuff *exp)
5133 struct nfsvattr forat;
5134 int error = 0, forat_ret = 1, gotproxystateid;
5136 struct nfsstate st, *stp = &st;
5137 struct nfslock lo, *lop = &lo;
5138 nfsv4stateid_t stateid;
5140 nfsattrbit_t attrbits;
5142 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5143 nd->nd_repstat = NFSERR_WRONGSEC;
5146 gotproxystateid = 0;
5147 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
5148 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5149 lop->lo_flags = NFSLCK_WRITE;
5150 stp->ls_ownerlen = 0;
5152 stp->ls_uid = nd->nd_cred->cr_uid;
5153 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
5154 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
5155 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
5156 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
5157 if ((nd->nd_flag & ND_NFSV41) != 0)
5158 clientid.qval = nd->nd_clientid.qval;
5159 else if (nd->nd_clientid.qval != clientid.qval)
5160 printf("EEK2 multiple clids\n");
5162 if ((nd->nd_flag & ND_NFSV41) != 0)
5163 printf("EEK! no clientid from session\n");
5164 nd->nd_flag |= ND_IMPLIEDCLID;
5165 nd->nd_clientid.qval = clientid.qval;
5167 stp->ls_stateid.other[2] = *tl++;
5169 * Don't allow this to be done for a DS.
5171 if ((nd->nd_flag & ND_DSSERVER) != 0)
5172 nd->nd_repstat = NFSERR_NOTSUPP;
5173 /* However, allow the proxy stateid. */
5174 if (stp->ls_stateid.seqid == 0xffffffff &&
5175 stp->ls_stateid.other[0] == 0x55555555 &&
5176 stp->ls_stateid.other[1] == 0x55555555 &&
5177 stp->ls_stateid.other[2] == 0x55555555)
5178 gotproxystateid = 1;
5179 off = fxdr_hyper(tl); tl += 2;
5180 lop->lo_first = off;
5181 len = fxdr_hyper(tl);
5182 lop->lo_end = off + len;
5184 * Paranoia, just in case it wraps around, which shouldn't
5185 * ever happen anyhow.
5187 if (nd->nd_repstat == 0 && (lop->lo_end < lop->lo_first || len <= 0))
5188 nd->nd_repstat = NFSERR_INVAL;
5190 if (nd->nd_repstat == 0 && vnode_vtype(vp) != VREG)
5191 nd->nd_repstat = NFSERR_WRONGTYPE;
5192 NFSZERO_ATTRBIT(&attrbits);
5193 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5194 forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits);
5195 if (nd->nd_repstat == 0)
5196 nd->nd_repstat = forat_ret;
5197 if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid ||
5198 NFSVNO_EXSTRICTACCESS(exp)))
5199 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp,
5200 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5202 if (nd->nd_repstat == 0 && gotproxystateid == 0)
5203 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
5204 &stateid, exp, nd, curthread);
5206 if (nd->nd_repstat == 0)
5207 nd->nd_repstat = nfsvno_allocate(vp, off, len, nd->nd_cred,
5210 NFSEXITCODE2(0, nd);
5214 NFSEXITCODE2(error, nd);
5222 nfsrvd_copy_file_range(struct nfsrv_descript *nd, __unused int isdgram,
5223 vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
5227 int cnt, error = 0, ret;
5228 off_t inoff, outoff;
5231 struct nfsstate inst, outst, *instp = &inst, *outstp = &outst;
5232 struct nfslock inlo, outlo, *inlop = &inlo, *outlop = &outlo;
5234 nfsv4stateid_t stateid;
5235 nfsattrbit_t attrbits;
5236 void *rl_rcookie, *rl_wcookie;
5238 rl_rcookie = rl_wcookie = NULL;
5239 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5240 nd->nd_repstat = NFSERR_WRONGSEC;
5243 if (nfsrv_devidcnt > 0) {
5245 * For a pNFS server, reply NFSERR_NOTSUPP so that the client
5246 * will do the copy via I/O on the DS(s).
5248 nd->nd_repstat = NFSERR_NOTSUPP;
5252 /* Copying a byte range within the same file is not allowed. */
5253 nd->nd_repstat = NFSERR_INVAL;
5256 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_STATEID + 3 * NFSX_HYPER +
5258 instp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
5259 inlop->lo_flags = NFSLCK_READ;
5260 instp->ls_ownerlen = 0;
5261 instp->ls_op = NULL;
5262 instp->ls_uid = nd->nd_cred->cr_uid;
5263 instp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5264 clientid.lval[0] = instp->ls_stateid.other[0] = *tl++;
5265 clientid.lval[1] = instp->ls_stateid.other[1] = *tl++;
5266 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0)
5267 clientid.qval = nd->nd_clientid.qval;
5268 instp->ls_stateid.other[2] = *tl++;
5269 outstp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5270 outlop->lo_flags = NFSLCK_WRITE;
5271 outstp->ls_ownerlen = 0;
5272 outstp->ls_op = NULL;
5273 outstp->ls_uid = nd->nd_cred->cr_uid;
5274 outstp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5275 outstp->ls_stateid.other[0] = *tl++;
5276 outstp->ls_stateid.other[1] = *tl++;
5277 outstp->ls_stateid.other[2] = *tl++;
5278 inoff = fxdr_hyper(tl); tl += 2;
5279 inlop->lo_first = inoff;
5280 outoff = fxdr_hyper(tl); tl += 2;
5281 outlop->lo_first = outoff;
5282 len = fxdr_hyper(tl); tl += 2;
5284 /* len == 0 means to EOF. */
5285 inlop->lo_end = OFF_MAX;
5286 outlop->lo_end = OFF_MAX;
5288 inlop->lo_end = inlop->lo_first + len;
5289 outlop->lo_end = outlop->lo_first + len;
5293 * At this time only consecutive, synchronous copy is supported,
5294 * so ca_consecutive and ca_synchronous can be ignored.
5298 cnt = fxdr_unsigned(int, *tl);
5299 if ((nd->nd_flag & ND_DSSERVER) != 0 || cnt != 0)
5300 nd->nd_repstat = NFSERR_NOTSUPP;
5301 if (nd->nd_repstat == 0 && (inoff > OFF_MAX || outoff > OFF_MAX ||
5302 inlop->lo_end > OFF_MAX || outlop->lo_end > OFF_MAX ||
5303 inlop->lo_end < inlop->lo_first || outlop->lo_end <
5305 nd->nd_repstat = NFSERR_INVAL;
5307 if (nd->nd_repstat == 0 && vnode_vtype(vp) != VREG)
5308 nd->nd_repstat = NFSERR_WRONGTYPE;
5310 /* Check permissions for the input file. */
5311 NFSZERO_ATTRBIT(&attrbits);
5312 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5313 ret = nfsvno_getattr(vp, &at, nd, curthread, 1, &attrbits);
5314 if (nd->nd_repstat == 0)
5315 nd->nd_repstat = ret;
5316 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5317 NFSVNO_EXSTRICTACCESS(exp)))
5318 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp,
5319 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5321 if (nd->nd_repstat == 0)
5322 nd->nd_repstat = nfsrv_lockctrl(vp, &instp, &inlop, NULL,
5323 clientid, &stateid, exp, nd, curthread);
5325 if (nd->nd_repstat != 0)
5328 error = NFSVOPLOCK(tovp, LK_SHARED);
5331 if (vnode_vtype(tovp) != VREG)
5332 nd->nd_repstat = NFSERR_WRONGTYPE;
5334 /* For the output file, we only need the Owner attribute. */
5335 ret = nfsvno_getattr(tovp, &at, nd, curthread, 1, &attrbits);
5336 if (nd->nd_repstat == 0)
5337 nd->nd_repstat = ret;
5338 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5339 NFSVNO_EXSTRICTACCESS(exp)))
5340 nd->nd_repstat = nfsvno_accchk(tovp, VWRITE, nd->nd_cred, toexp,
5341 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5343 if (nd->nd_repstat == 0)
5344 nd->nd_repstat = nfsrv_lockctrl(tovp, &outstp, &outlop, NULL,
5345 clientid, &stateid, toexp, nd, curthread);
5348 /* Range lock the byte ranges for both invp and outvp. */
5349 if (nd->nd_repstat == 0) {
5352 rl_wcookie = vn_rangelock_wlock(tovp, outoff,
5354 rl_rcookie = vn_rangelock_tryrlock(vp, inoff,
5357 rl_wcookie = vn_rangelock_wlock(tovp, outoff,
5359 rl_rcookie = vn_rangelock_tryrlock(vp, inoff,
5362 if (rl_rcookie != NULL)
5364 vn_rangelock_unlock(tovp, rl_wcookie);
5366 rl_rcookie = vn_rangelock_rlock(vp, inoff,
5369 rl_rcookie = vn_rangelock_rlock(vp, inoff,
5371 vn_rangelock_unlock(vp, rl_rcookie);
5374 error = NFSVOPLOCK(vp, LK_SHARED);
5376 ret = nfsvno_getattr(vp, &at, nd, curthread, 1, NULL);
5379 * Since invp is range locked, na_size should
5382 if (len == 0 && at.na_size > inoff) {
5384 * If len == 0, set it based on invp's
5385 * size. If offset is past EOF, just
5388 len = at.na_size - inoff;
5389 } else if (nfsrv_linux42server == 0 &&
5390 inoff + len > at.na_size) {
5392 * RFC-7862 says that NFSERR_INVAL must
5393 * be returned when inoff + len exceeds
5394 * the file size, however the NFSv4.2
5395 * Linux client likes to do this, so
5396 * only check if nfsrv_linux42server
5399 nd->nd_repstat = NFSERR_INVAL;
5403 if (ret != 0 && nd->nd_repstat == 0)
5404 nd->nd_repstat = ret;
5405 } else if (nd->nd_repstat == 0)
5406 nd->nd_repstat = error;
5410 * Do the actual copy to an upper limit of vfs.nfs.maxcopyrange.
5411 * This limit is applied to ensure that the RPC replies in a
5414 if (len > nfs_maxcopyrange)
5415 xfer = nfs_maxcopyrange;
5418 if (nd->nd_repstat == 0) {
5419 nd->nd_repstat = vn_copy_file_range(vp, &inoff, tovp, &outoff,
5420 &xfer, 0, nd->nd_cred, nd->nd_cred, NULL);
5421 if (nd->nd_repstat == 0)
5425 /* Unlock the ranges. */
5426 if (rl_rcookie != NULL)
5427 vn_rangelock_unlock(vp, rl_rcookie);
5428 if (rl_wcookie != NULL)
5429 vn_rangelock_unlock(tovp, rl_wcookie);
5431 if (nd->nd_repstat == 0) {
5432 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_HYPER +
5434 *tl++ = txdr_unsigned(0); /* No callback ids. */
5435 txdr_hyper(len, tl); tl += 2;
5436 *tl++ = txdr_unsigned(NFSWRITE_UNSTABLE);
5437 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
5438 *tl++ = txdr_unsigned(nfsboottime.tv_usec);
5439 *tl++ = newnfs_true;
5445 NFSEXITCODE2(error, nd);
5450 NFSEXITCODE2(error, nd);
5458 nfsrvd_seek(struct nfsrv_descript *nd, __unused int isdgram,
5459 vnode_t vp, struct nfsexstuff *exp)
5463 int content, error = 0;
5466 nfsattrbit_t attrbits;
5469 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5470 nd->nd_repstat = NFSERR_WRONGSEC;
5473 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + NFSX_HYPER + NFSX_UNSIGNED);
5474 /* Ignore the stateid for now. */
5475 tl += (NFSX_STATEID / NFSX_UNSIGNED);
5476 off = fxdr_hyper(tl); tl += 2;
5477 content = fxdr_unsigned(int, *tl);
5478 if (content == NFSV4CONTENT_DATA)
5480 else if (content == NFSV4CONTENT_HOLE)
5483 nd->nd_repstat = NFSERR_BADXDR;
5484 if (nd->nd_repstat == 0 && vnode_vtype(vp) == VDIR)
5485 nd->nd_repstat = NFSERR_ISDIR;
5486 if (nd->nd_repstat == 0 && vnode_vtype(vp) != VREG)
5487 nd->nd_repstat = NFSERR_WRONGTYPE;
5488 if (nd->nd_repstat == 0 && off < 0)
5489 nd->nd_repstat = NFSERR_NXIO;
5490 if (nd->nd_repstat == 0) {
5491 /* Check permissions for the input file. */
5492 NFSZERO_ATTRBIT(&attrbits);
5493 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5494 nd->nd_repstat = nfsvno_getattr(vp, &at, nd, curthread, 1,
5497 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5498 NFSVNO_EXSTRICTACCESS(exp)))
5499 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp,
5500 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5502 if (nd->nd_repstat != 0)
5505 /* nfsvno_seek() unlocks and vrele()s the vp. */
5506 nd->nd_repstat = nfsvno_seek(nd, vp, cmd, &off, content, &eof,
5507 nd->nd_cred, curthread);
5508 if (nd->nd_repstat == 0 && eof && content == NFSV4CONTENT_DATA &&
5509 nfsrv_linux42server != 0)
5510 nd->nd_repstat = NFSERR_NXIO;
5511 if (nd->nd_repstat == 0) {
5512 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER);
5514 *tl++ = newnfs_true;
5516 *tl++ = newnfs_false;
5517 txdr_hyper(off, tl);
5519 NFSEXITCODE2(error, nd);
5523 NFSEXITCODE2(error, nd);
5528 * nfs get extended attribute service
5531 nfsrvd_getxattr(struct nfsrv_descript *nd, __unused int isdgram,
5532 vnode_t vp, __unused struct nfsexstuff *exp)
5535 struct mbuf *mp = NULL, *mpend = NULL;
5538 struct thread *p = curthread;
5541 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5542 nd->nd_repstat = NFSERR_WRONGSEC;
5545 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5546 len = fxdr_unsigned(int, *tl);
5548 nd->nd_repstat = NFSERR_BADXDR;
5551 if (len > EXTATTR_MAXNAMELEN) {
5552 nd->nd_repstat = NFSERR_NOXATTR;
5555 name = malloc(len + 1, M_TEMP, M_WAITOK);
5556 nd->nd_repstat = nfsrv_mtostr(nd, name, len);
5557 if (nd->nd_repstat == 0)
5558 nd->nd_repstat = nfsvno_getxattr(vp, name, nd->nd_maxresp,
5559 nd->nd_cred, p, &mp, &mpend, &len);
5560 if (nd->nd_repstat == ENOATTR)
5561 nd->nd_repstat = NFSERR_NOXATTR;
5562 else if (nd->nd_repstat == EOPNOTSUPP)
5563 nd->nd_repstat = NFSERR_NOTSUPP;
5564 if (nd->nd_repstat == 0) {
5565 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5566 *tl = txdr_unsigned(len);
5568 nd->nd_mb->m_next = mp;
5570 nd->nd_bpos = mtod(mpend, caddr_t) + mpend->m_len;
5576 if (nd->nd_repstat == 0)
5577 nd->nd_repstat = error;
5579 NFSEXITCODE2(0, nd);
5584 * nfs set extended attribute service
5587 nfsrvd_setxattr(struct nfsrv_descript *nd, __unused int isdgram,
5588 vnode_t vp, __unused struct nfsexstuff *exp)
5591 struct nfsvattr ova, nva;
5592 nfsattrbit_t attrbits;
5593 int error, len, opt;
5596 struct thread *p = curthread;
5600 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5601 nd->nd_repstat = NFSERR_WRONGSEC;
5604 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
5605 opt = fxdr_unsigned(int, *tl++);
5606 len = fxdr_unsigned(int, *tl);
5608 nd->nd_repstat = NFSERR_BADXDR;
5611 if (len > EXTATTR_MAXNAMELEN) {
5612 nd->nd_repstat = NFSERR_NOXATTR;
5615 name = malloc(len + 1, M_TEMP, M_WAITOK);
5616 error = nfsrv_mtostr(nd, name, len);
5619 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5620 len = fxdr_unsigned(int, *tl);
5621 if (len < 0 || len > IOSIZE_MAX) {
5622 nd->nd_repstat = NFSERR_XATTR2BIG;
5626 case NFSV4SXATTR_CREATE:
5627 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL,
5628 &siz, nd->nd_cred, p);
5629 if (error != ENOATTR)
5630 nd->nd_repstat = NFSERR_EXIST;
5633 case NFSV4SXATTR_REPLACE:
5634 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL,
5635 &siz, nd->nd_cred, p);
5637 nd->nd_repstat = NFSERR_NOXATTR;
5639 case NFSV4SXATTR_EITHER:
5642 nd->nd_repstat = NFSERR_BADXDR;
5644 if (nd->nd_repstat != 0)
5647 /* Now, do the Set Extended attribute, with Change before and after. */
5648 NFSZERO_ATTRBIT(&attrbits);
5649 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
5650 nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits);
5651 if (nd->nd_repstat == 0) {
5652 nd->nd_repstat = nfsvno_setxattr(vp, name, len, nd->nd_md,
5653 nd->nd_dpos, nd->nd_cred, p);
5654 if (nd->nd_repstat == ENXIO)
5655 nd->nd_repstat = NFSERR_XATTR2BIG;
5657 if (nd->nd_repstat == 0 && len > 0)
5658 nd->nd_repstat = nfsm_advance(nd, NFSM_RNDUP(len), -1);
5659 if (nd->nd_repstat == 0)
5660 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
5661 if (nd->nd_repstat == 0) {
5662 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED);
5663 *tl++ = newnfs_true;
5664 txdr_hyper(ova.na_filerev, tl); tl += 2;
5665 txdr_hyper(nva.na_filerev, tl);
5670 if (nd->nd_repstat == 0)
5671 nd->nd_repstat = error;
5673 NFSEXITCODE2(0, nd);
5678 * nfs remove extended attribute service
5681 nfsrvd_rmxattr(struct nfsrv_descript *nd, __unused int isdgram,
5682 vnode_t vp, __unused struct nfsexstuff *exp)
5685 struct nfsvattr ova, nva;
5686 nfsattrbit_t attrbits;
5689 struct thread *p = curthread;
5693 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5694 nd->nd_repstat = NFSERR_WRONGSEC;
5697 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5698 len = fxdr_unsigned(int, *tl);
5700 nd->nd_repstat = NFSERR_BADXDR;
5703 if (len > EXTATTR_MAXNAMELEN) {
5704 nd->nd_repstat = NFSERR_NOXATTR;
5707 name = malloc(len + 1, M_TEMP, M_WAITOK);
5708 error = nfsrv_mtostr(nd, name, len);
5712 if ((nd->nd_flag & ND_IMPLIEDCLID) == 0) {
5713 printf("EEK! nfsrvd_rmxattr: no implied clientid\n");
5714 error = NFSERR_NOXATTR;
5718 * Now, do the Remove Extended attribute, with Change before and
5721 NFSZERO_ATTRBIT(&attrbits);
5722 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
5723 nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits);
5724 if (nd->nd_repstat == 0) {
5725 nd->nd_repstat = nfsvno_rmxattr(nd, vp, name, nd->nd_cred, p);
5726 if (nd->nd_repstat == ENOATTR)
5727 nd->nd_repstat = NFSERR_NOXATTR;
5729 if (nd->nd_repstat == 0)
5730 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
5731 if (nd->nd_repstat == 0) {
5732 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED);
5733 *tl++ = newnfs_true;
5734 txdr_hyper(ova.na_filerev, tl); tl += 2;
5735 txdr_hyper(nva.na_filerev, tl);
5740 if (nd->nd_repstat == 0)
5741 nd->nd_repstat = error;
5743 NFSEXITCODE2(0, nd);
5748 * nfs list extended attribute service
5751 nfsrvd_listxattr(struct nfsrv_descript *nd, __unused int isdgram,
5752 vnode_t vp, __unused struct nfsexstuff *exp)
5754 uint32_t cnt, *tl, len, len2, i, pos, retlen;
5756 uint64_t cookie, cookie2;
5759 struct thread *p = curthread;
5763 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5764 nd->nd_repstat = NFSERR_WRONGSEC;
5767 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
5769 * The cookie doesn't need to be in net byte order, but FreeBSD
5770 * does so to make it more readable in packet traces.
5772 cookie = fxdr_hyper(tl); tl += 2;
5773 len = fxdr_unsigned(uint32_t, *tl);
5774 if (len == 0 || cookie >= IOSIZE_MAX) {
5775 nd->nd_repstat = NFSERR_BADXDR;
5778 if (len > nd->nd_maxresp - NFS_MAXXDR)
5779 len = nd->nd_maxresp - NFS_MAXXDR;
5781 nd->nd_repstat = nfsvno_listxattr(vp, cookie, nd->nd_cred, p, &buf,
5783 if (nd->nd_repstat == EOPNOTSUPP)
5784 nd->nd_repstat = NFSERR_NOTSUPP;
5785 if (nd->nd_repstat == 0) {
5786 cookie2 = cookie + len;
5787 if (cookie2 < cookie)
5788 nd->nd_repstat = NFSERR_BADXDR;
5790 if (nd->nd_repstat == 0) {
5791 /* Now copy the entries out. */
5792 retlen = NFSX_HYPER + 2 * NFSX_UNSIGNED;
5793 if (len == 0 && retlen <= len2) {
5794 /* The cookie was at eof. */
5795 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 *
5797 txdr_hyper(cookie2, tl); tl += 2;
5798 *tl++ = txdr_unsigned(0);
5803 /* Sanity check the cookie. */
5804 for (pos = 0; pos < len; pos += (i + 1)) {
5809 if (pos != cookie) {
5810 nd->nd_repstat = NFSERR_INVAL;
5814 /* Loop around copying the entrie(s) out. */
5818 while (i < len && len2 >= retlen + NFSM_RNDUP(i) +
5821 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER +
5823 txdr_hyper(cookie2, tl); tl += 2;
5825 retlen += nfsm_strtom(nd, &buf[pos + 1], i);
5832 * eof is set true/false by nfsvno_listxattr(), but if we
5833 * can't copy all entries returned by nfsvno_listxattr(),
5834 * we are not at eof.
5839 /* *tl is set above. */
5840 *tl = txdr_unsigned(cnt);
5841 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5847 nd->nd_repstat = NFSERR_TOOSMALL;
5852 if (nd->nd_repstat == 0)
5853 nd->nd_repstat = error;
5855 NFSEXITCODE2(0, nd);
5860 * nfsv4 service not supported
5863 nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram,
5864 __unused vnode_t vp, __unused struct nfsexstuff *exp)
5867 nd->nd_repstat = NFSERR_NOTSUPP;
5868 NFSEXITCODE2(0, nd);