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(vnode_mount(vp)) & 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);
693 nd->nd_mb->m_next = mp;
695 nd->nd_bpos = mtod(mpend, caddr_t) + mpend->m_len;
706 nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
707 vnode_t vp, struct nfsexstuff *exp)
710 int error = 0, cnt, getret = 1, gotproxystateid, reqlen, eof = 0;
711 struct mbuf *m2, *m3;
714 struct nfsstate st, *stp = &st;
715 struct nfslock lo, *lop = &lo;
716 nfsv4stateid_t stateid;
718 struct thread *p = curthread;
720 if (nd->nd_repstat) {
721 nfsrv_postopattr(nd, getret, &nva);
724 if (nd->nd_flag & ND_NFSV2) {
725 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
726 off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
727 reqlen = fxdr_unsigned(int, *tl);
728 } else if (nd->nd_flag & ND_NFSV3) {
729 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
730 off = fxdr_hyper(tl);
732 reqlen = fxdr_unsigned(int, *tl);
734 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
735 reqlen = fxdr_unsigned(int, *(tl + 6));
737 if (reqlen > NFS_SRVMAXDATA(nd)) {
738 reqlen = NFS_SRVMAXDATA(nd);
739 } else if (reqlen < 0) {
744 if (nd->nd_flag & ND_NFSV4) {
745 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
746 lop->lo_flags = NFSLCK_READ;
747 stp->ls_ownerlen = 0;
749 stp->ls_uid = nd->nd_cred->cr_uid;
750 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
751 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
752 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
753 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
754 if ((nd->nd_flag & ND_NFSV41) != 0)
755 clientid.qval = nd->nd_clientid.qval;
756 else if (nd->nd_clientid.qval != clientid.qval)
757 printf("EEK1 multiple clids\n");
759 if ((nd->nd_flag & ND_NFSV41) != 0)
760 printf("EEK! no clientid from session\n");
761 nd->nd_flag |= ND_IMPLIEDCLID;
762 nd->nd_clientid.qval = clientid.qval;
764 stp->ls_stateid.other[2] = *tl++;
766 * Don't allow the client to use a special stateid for a DS op.
768 if ((nd->nd_flag & ND_DSSERVER) != 0 &&
769 ((stp->ls_stateid.other[0] == 0x0 &&
770 stp->ls_stateid.other[1] == 0x0 &&
771 stp->ls_stateid.other[2] == 0x0) ||
772 (stp->ls_stateid.other[0] == 0xffffffff &&
773 stp->ls_stateid.other[1] == 0xffffffff &&
774 stp->ls_stateid.other[2] == 0xffffffff) ||
775 stp->ls_stateid.seqid != 0))
776 nd->nd_repstat = NFSERR_BADSTATEID;
777 /* However, allow the proxy stateid. */
778 if (stp->ls_stateid.seqid == 0xffffffff &&
779 stp->ls_stateid.other[0] == 0x55555555 &&
780 stp->ls_stateid.other[1] == 0x55555555 &&
781 stp->ls_stateid.other[2] == 0x55555555)
783 off = fxdr_hyper(tl);
786 lop->lo_end = off + reqlen;
788 * Paranoia, just in case it wraps around.
790 if (lop->lo_end < off)
791 lop->lo_end = NFS64BITSSET;
793 if (vnode_vtype(vp) != VREG) {
794 if (nd->nd_flag & ND_NFSV3)
795 nd->nd_repstat = EINVAL;
797 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
800 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
802 nd->nd_repstat = getret;
803 if (!nd->nd_repstat &&
804 (nva.na_uid != nd->nd_cred->cr_uid ||
805 NFSVNO_EXSTRICTACCESS(exp))) {
806 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
808 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
810 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
811 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
812 NFSACCCHK_VPISLOCKED, NULL);
815 * DS reads are marked by ND_DSSERVER or use the proxy special
818 if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) ==
819 ND_NFSV4 && gotproxystateid == 0)
820 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
821 &stateid, exp, nd, p);
822 if (nd->nd_repstat) {
824 if (nd->nd_flag & ND_NFSV3)
825 nfsrv_postopattr(nd, getret, &nva);
828 if (off >= nva.na_size) {
831 } else if (reqlen == 0)
833 else if ((off + reqlen) >= nva.na_size) {
834 cnt = nva.na_size - off;
840 nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p,
842 if (!(nd->nd_flag & ND_NFSV4)) {
843 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
845 nd->nd_repstat = getret;
847 if (nd->nd_repstat) {
851 if (nd->nd_flag & ND_NFSV3)
852 nfsrv_postopattr(nd, getret, &nva);
857 if (nd->nd_flag & ND_NFSV2) {
858 nfsrv_fillattr(nd, &nva);
859 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
861 if (nd->nd_flag & ND_NFSV3) {
862 nfsrv_postopattr(nd, getret, &nva);
863 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
864 *tl++ = txdr_unsigned(cnt);
866 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
870 *tl++ = newnfs_false;
872 *tl = txdr_unsigned(cnt);
874 nd->nd_mb->m_next = m3;
876 nd->nd_bpos = mtod(m2, caddr_t) + m2->m_len;
884 NFSEXITCODE2(error, nd);
892 nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
893 vnode_t vp, struct nfsexstuff *exp)
896 struct nfsvattr nva, forat;
897 int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
898 int gotproxystateid, stable = NFSWRITE_FILESYNC;
900 struct nfsstate st, *stp = &st;
901 struct nfslock lo, *lop = &lo;
902 nfsv4stateid_t stateid;
904 nfsattrbit_t attrbits;
905 struct thread *p = curthread;
907 if (nd->nd_repstat) {
908 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
912 if (nd->nd_flag & ND_NFSV2) {
913 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
914 off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
916 retlen = len = fxdr_unsigned(int32_t, *tl);
917 } else if (nd->nd_flag & ND_NFSV3) {
918 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
919 off = fxdr_hyper(tl);
921 stable = fxdr_unsigned(int, *tl++);
922 retlen = len = fxdr_unsigned(int32_t, *tl);
924 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
925 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
926 lop->lo_flags = NFSLCK_WRITE;
927 stp->ls_ownerlen = 0;
929 stp->ls_uid = nd->nd_cred->cr_uid;
930 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
931 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
932 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
933 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
934 if ((nd->nd_flag & ND_NFSV41) != 0)
935 clientid.qval = nd->nd_clientid.qval;
936 else if (nd->nd_clientid.qval != clientid.qval)
937 printf("EEK2 multiple clids\n");
939 if ((nd->nd_flag & ND_NFSV41) != 0)
940 printf("EEK! no clientid from session\n");
941 nd->nd_flag |= ND_IMPLIEDCLID;
942 nd->nd_clientid.qval = clientid.qval;
944 stp->ls_stateid.other[2] = *tl++;
946 * Don't allow the client to use a special stateid for a DS op.
948 if ((nd->nd_flag & ND_DSSERVER) != 0 &&
949 ((stp->ls_stateid.other[0] == 0x0 &&
950 stp->ls_stateid.other[1] == 0x0 &&
951 stp->ls_stateid.other[2] == 0x0) ||
952 (stp->ls_stateid.other[0] == 0xffffffff &&
953 stp->ls_stateid.other[1] == 0xffffffff &&
954 stp->ls_stateid.other[2] == 0xffffffff) ||
955 stp->ls_stateid.seqid != 0))
956 nd->nd_repstat = NFSERR_BADSTATEID;
957 /* However, allow the proxy stateid. */
958 if (stp->ls_stateid.seqid == 0xffffffff &&
959 stp->ls_stateid.other[0] == 0x55555555 &&
960 stp->ls_stateid.other[1] == 0x55555555 &&
961 stp->ls_stateid.other[2] == 0x55555555)
963 off = fxdr_hyper(tl);
966 stable = fxdr_unsigned(int, *tl++);
967 retlen = len = fxdr_unsigned(int32_t, *tl);
968 lop->lo_end = off + len;
970 * Paranoia, just in case it wraps around, which shouldn't
971 * ever happen anyhow.
973 if (lop->lo_end < lop->lo_first)
974 lop->lo_end = NFS64BITSSET;
977 if (retlen > NFS_SRVMAXIO || retlen < 0)
978 nd->nd_repstat = EIO;
979 if (vnode_vtype(vp) != VREG && !nd->nd_repstat) {
980 if (nd->nd_flag & ND_NFSV3)
981 nd->nd_repstat = EINVAL;
983 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
986 NFSZERO_ATTRBIT(&attrbits);
987 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
988 forat_ret = nfsvno_getattr(vp, &forat, nd, p, 1, &attrbits);
990 nd->nd_repstat = forat_ret;
991 if (!nd->nd_repstat &&
992 (forat.na_uid != nd->nd_cred->cr_uid ||
993 NFSVNO_EXSTRICTACCESS(exp)))
994 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
996 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
998 * DS reads are marked by ND_DSSERVER or use the proxy special
1001 if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) ==
1002 ND_NFSV4 && gotproxystateid == 0)
1003 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
1004 &stateid, exp, nd, p);
1005 if (nd->nd_repstat) {
1007 if (nd->nd_flag & ND_NFSV3)
1008 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
1013 * For NFS Version 2, it is not obvious what a write of zero length
1014 * should do, but I might as well be consistent with Version 3,
1015 * which is to return ok so long as there are no permission problems.
1018 nd->nd_repstat = nfsvno_write(vp, off, retlen, &stable,
1019 nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
1020 error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
1024 if (nd->nd_flag & ND_NFSV4)
1027 aftat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
1029 if (!nd->nd_repstat)
1030 nd->nd_repstat = aftat_ret;
1031 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1032 if (nd->nd_flag & ND_NFSV3)
1033 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
1036 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1037 *tl++ = txdr_unsigned(retlen);
1039 * If nfs_async is set, then pretend the write was FILESYNC.
1040 * Warning: Doing this violates RFC1813 and runs a risk
1041 * of data written by a client being lost when the server
1044 if (stable == NFSWRITE_UNSTABLE && nfs_async == 0)
1045 *tl++ = txdr_unsigned(stable);
1047 *tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
1049 * Actually, there is no need to txdr these fields,
1050 * but it may make the values more human readable,
1051 * for debugging purposes.
1053 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
1054 *tl = txdr_unsigned(nfsboottime.tv_usec);
1055 } else if (!nd->nd_repstat)
1056 nfsrv_fillattr(nd, &nva);
1059 NFSEXITCODE2(0, nd);
1063 NFSEXITCODE2(error, nd);
1068 * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
1069 * now does a truncate to 0 length via. setattr if it already exists
1070 * The core creation routine has been extracted out into nfsrv_creatsub(),
1071 * so it can also be used by nfsrv_open() for V4.
1074 nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
1075 vnode_t dp, struct nfsexstuff *exp)
1077 struct nfsvattr nva, dirfor, diraft;
1078 struct nfsv2_sattr *sp;
1079 struct nameidata named;
1081 int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
1082 int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
1084 vnode_t vp = NULL, dirp = NULL;
1089 int32_t cverf[2], tverf[2] = { 0, 0 };
1090 struct thread *p = curthread;
1092 if (nd->nd_repstat) {
1093 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1096 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1097 LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
1098 nfsvno_setpathbuf(&named, &bufp, &hashp);
1099 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1102 if (!nd->nd_repstat) {
1103 NFSVNO_ATTRINIT(&nva);
1104 if (nd->nd_flag & ND_NFSV2) {
1105 NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1106 vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
1109 NFSVNO_SETATTRVAL(&nva, type, vtyp);
1110 NFSVNO_SETATTRVAL(&nva, mode,
1111 nfstov_mode(sp->sa_mode));
1112 switch (nva.na_type) {
1114 tsize = fxdr_unsigned(int32_t, sp->sa_size);
1116 NFSVNO_SETATTRVAL(&nva, size,
1122 rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
1128 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1129 how = fxdr_unsigned(int, *tl);
1131 case NFSCREATE_GUARDED:
1132 case NFSCREATE_UNCHECKED:
1133 error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
1137 case NFSCREATE_EXCLUSIVE:
1138 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
1144 NFSVNO_SETATTRVAL(&nva, type, VREG);
1147 if (nd->nd_repstat) {
1148 nfsvno_relpathbuf(&named);
1149 if (nd->nd_flag & ND_NFSV3) {
1150 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 1,
1152 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1159 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1161 if (nd->nd_flag & ND_NFSV2) {
1165 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1169 if (nd->nd_repstat) {
1170 if (nd->nd_flag & ND_NFSV3)
1171 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1178 if (!(nd->nd_flag & ND_NFSV2)) {
1180 case NFSCREATE_GUARDED:
1182 nd->nd_repstat = EEXIST;
1184 case NFSCREATE_UNCHECKED:
1186 case NFSCREATE_EXCLUSIVE:
1187 if (named.ni_vp == NULL)
1188 NFSVNO_SETATTRVAL(&nva, mode, 0);
1194 * Iff doesn't exist, create it
1195 * otherwise just truncate to 0 length
1196 * should I set the mode too ?
1198 nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
1199 &exclusive_flag, cverf, rdev, exp);
1201 if (!nd->nd_repstat) {
1202 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
1203 if (!nd->nd_repstat)
1204 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
1207 if (!nd->nd_repstat) {
1208 tverf[0] = nva.na_atime.tv_sec;
1209 tverf[1] = nva.na_atime.tv_nsec;
1212 if (nd->nd_flag & ND_NFSV2) {
1213 if (!nd->nd_repstat) {
1214 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
1215 nfsrv_fillattr(nd, &nva);
1218 if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
1219 || cverf[1] != tverf[1]))
1220 nd->nd_repstat = EEXIST;
1221 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1223 if (!nd->nd_repstat) {
1224 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
1225 nfsrv_postopattr(nd, 0, &nva);
1227 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1231 NFSEXITCODE2(0, nd);
1235 nfsvno_relpathbuf(&named);
1236 NFSEXITCODE2(error, nd);
1241 * nfs v3 mknod service (and v4 create)
1244 nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
1245 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
1247 struct nfsvattr nva, dirfor, diraft;
1249 struct nameidata named;
1250 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1251 u_int32_t major, minor;
1252 enum vtype vtyp = VNON;
1253 nfstype nfs4type = NFNON;
1254 vnode_t vp, dirp = NULL;
1255 nfsattrbit_t attrbits;
1256 char *bufp = NULL, *pathcp = NULL;
1257 u_long *hashp, cnflags;
1258 NFSACL_T *aclp = NULL;
1259 struct thread *p = curthread;
1261 NFSVNO_ATTRINIT(&nva);
1262 cnflags = (LOCKPARENT | SAVESTART);
1263 if (nd->nd_repstat) {
1264 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1267 #ifdef NFS4_ACL_EXTATTR_NAME
1268 aclp = acl_alloc(M_WAITOK);
1273 * For V4, the creation stuff is here, Yuck!
1275 if (nd->nd_flag & ND_NFSV4) {
1276 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1277 vtyp = nfsv34tov_type(*tl);
1278 nfs4type = fxdr_unsigned(nfstype, *tl);
1281 error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
1288 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1289 major = fxdr_unsigned(u_int32_t, *tl++);
1290 minor = fxdr_unsigned(u_int32_t, *tl);
1291 nva.na_rdev = NFSMAKEDEV(major, minor);
1297 cnflags = (LOCKPARENT | SAVENAME);
1300 nd->nd_repstat = NFSERR_BADTYPE;
1302 #ifdef NFS4_ACL_EXTATTR_NAME
1308 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags | NOCACHE);
1309 nfsvno_setpathbuf(&named, &bufp, &hashp);
1310 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1313 if (!nd->nd_repstat) {
1314 if (nd->nd_flag & ND_NFSV3) {
1315 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1316 vtyp = nfsv34tov_type(*tl);
1318 error = nfsrv_sattr(nd, NULL, &nva, &attrbits, aclp, p);
1322 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
1323 (vtyp == VCHR || vtyp == VBLK)) {
1324 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1325 major = fxdr_unsigned(u_int32_t, *tl++);
1326 minor = fxdr_unsigned(u_int32_t, *tl);
1327 nva.na_rdev = NFSMAKEDEV(major, minor);
1331 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
1332 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
1333 if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
1334 dirfor.na_gid == nva.na_gid)
1335 NFSVNO_UNSET(&nva, gid);
1336 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
1338 if (nd->nd_repstat) {
1340 #ifdef NFS4_ACL_EXTATTR_NAME
1343 nfsvno_relpathbuf(&named);
1345 free(pathcp, M_TEMP);
1346 if (nd->nd_flag & ND_NFSV3)
1347 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1353 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
1354 * in va_mode, so we'll have to set a default here.
1356 if (NFSVNO_NOTSETMODE(&nva)) {
1364 named.ni_cnd.cn_flags |= WILLBEDIR;
1365 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1366 if (nd->nd_repstat) {
1368 if (nd->nd_flag & ND_NFSV3)
1369 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd,
1373 #ifdef NFS4_ACL_EXTATTR_NAME
1376 if (nd->nd_flag & ND_NFSV3)
1377 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1382 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
1384 if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
1386 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
1387 &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
1389 #ifdef NFS4_ACL_EXTATTR_NAME
1393 } else if (vtyp == VLNK) {
1394 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1395 &dirfor, &diraft, &diraft_ret, &attrbits,
1396 aclp, p, exp, pathcp, pathlen);
1397 #ifdef NFS4_ACL_EXTATTR_NAME
1400 free(pathcp, M_TEMP);
1405 nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
1406 if (!nd->nd_repstat) {
1408 nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
1409 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1410 if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
1411 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
1413 if (vpp != NULL && nd->nd_repstat == 0) {
1420 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1422 if (!nd->nd_repstat) {
1423 if (nd->nd_flag & ND_NFSV3) {
1424 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1425 nfsrv_postopattr(nd, 0, &nva);
1427 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1428 *tl++ = newnfs_false;
1429 txdr_hyper(dirfor.na_filerev, tl);
1431 txdr_hyper(diraft.na_filerev, tl);
1432 (void) nfsrv_putattrbit(nd, &attrbits);
1435 if (nd->nd_flag & ND_NFSV3)
1436 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1437 #ifdef NFS4_ACL_EXTATTR_NAME
1442 NFSEXITCODE2(0, nd);
1446 #ifdef NFS4_ACL_EXTATTR_NAME
1450 nfsvno_relpathbuf(&named);
1452 free(pathcp, M_TEMP);
1454 NFSEXITCODE2(error, nd);
1459 * nfs remove service
1462 nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
1463 vnode_t dp, struct nfsexstuff *exp)
1465 struct nameidata named;
1467 int error = 0, dirfor_ret = 1, diraft_ret = 1;
1468 vnode_t dirp = NULL;
1469 struct nfsvattr dirfor, diraft;
1472 struct thread *p = curthread;
1474 if (nd->nd_repstat) {
1475 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1478 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
1479 LOCKPARENT | LOCKLEAF);
1480 nfsvno_setpathbuf(&named, &bufp, &hashp);
1481 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1484 nfsvno_relpathbuf(&named);
1487 if (!nd->nd_repstat) {
1488 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1491 nfsvno_relpathbuf(&named);
1494 if (!(nd->nd_flag & ND_NFSV2)) {
1495 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1502 if (!nd->nd_repstat) {
1503 if (nd->nd_flag & ND_NFSV4) {
1504 if (vnode_vtype(named.ni_vp) == VDIR)
1505 nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
1506 nd->nd_cred, p, exp);
1508 nd->nd_repstat = nfsvno_removesub(&named, 1,
1509 nd->nd_cred, p, exp);
1510 } else if (nd->nd_procnum == NFSPROC_RMDIR) {
1511 nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
1512 nd->nd_cred, p, exp);
1514 nd->nd_repstat = nfsvno_removesub(&named, 0,
1515 nd->nd_cred, p, exp);
1518 if (!(nd->nd_flag & ND_NFSV2)) {
1520 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0,
1524 if (nd->nd_flag & ND_NFSV3) {
1525 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1527 } else if (!nd->nd_repstat) {
1528 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1529 *tl++ = newnfs_false;
1530 txdr_hyper(dirfor.na_filerev, tl);
1532 txdr_hyper(diraft.na_filerev, tl);
1537 NFSEXITCODE2(error, nd);
1542 * nfs rename service
1545 nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
1546 vnode_t dp, vnode_t todp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
1549 int error = 0, fdirfor_ret = 1, fdiraft_ret = 1;
1550 int tdirfor_ret = 1, tdiraft_ret = 1;
1551 struct nameidata fromnd, tond;
1552 vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
1553 struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
1554 struct nfsexstuff tnes;
1556 char *bufp, *tbufp = NULL;
1559 struct thread *p = curthread;
1561 if (nd->nd_repstat) {
1562 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1563 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1566 if (!(nd->nd_flag & ND_NFSV2))
1567 fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd, p, 1, NULL);
1568 tond.ni_cnd.cn_nameiop = 0;
1569 tond.ni_startdir = NULL;
1570 NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART);
1571 nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
1572 error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
1577 nfsvno_relpathbuf(&fromnd);
1581 * Unlock dp in this code section, so it is unlocked before
1582 * tdp gets locked. This avoids a potential LOR if tdp is the
1583 * parent directory of dp.
1585 if (nd->nd_flag & ND_NFSV4) {
1590 /* Might lock tdp. */
1591 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 0,
1594 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1,
1599 tfh.nfsrvfh_len = 0;
1600 error = nfsrv_mtofh(nd, &tfh);
1602 error = nfsvno_getfh(dp, &fh, p);
1605 /* todp is always NULL except NFSv4 */
1606 nfsvno_relpathbuf(&fromnd);
1610 /* If this is the same file handle, just VREF() the vnode. */
1611 if (tfh.nfsrvfh_len == NFSX_MYFH &&
1612 !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
1616 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1,
1621 nd->nd_cred->cr_uid = nd->nd_saveduid;
1622 nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
1623 0); /* Locks tdp. */
1625 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd,
1631 NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
1632 nfsvno_setpathbuf(&tond, &tbufp, &hashp);
1633 if (!nd->nd_repstat) {
1634 error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
1639 nfsvno_relpathbuf(&fromnd);
1640 nfsvno_relpathbuf(&tond);
1644 if (nd->nd_repstat) {
1645 if (nd->nd_flag & ND_NFSV3) {
1646 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1648 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1654 nfsvno_relpathbuf(&fromnd);
1655 nfsvno_relpathbuf(&tond);
1660 * Done parsing, now down to business.
1662 nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, p, &fdirp);
1663 if (nd->nd_repstat) {
1664 if (nd->nd_flag & ND_NFSV3) {
1665 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1667 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1674 nfsvno_relpathbuf(&tond);
1677 if (vnode_vtype(fromnd.ni_vp) == VDIR)
1678 tond.ni_cnd.cn_flags |= WILLBEDIR;
1679 nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
1680 nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
1681 nd->nd_flag, nd->nd_cred, p);
1683 fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd, p, 0, NULL);
1685 tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd, p, 0, NULL);
1690 if (nd->nd_flag & ND_NFSV3) {
1691 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1692 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1693 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1694 NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
1695 *tl++ = newnfs_false;
1696 txdr_hyper(fdirfor.na_filerev, tl);
1698 txdr_hyper(fdiraft.na_filerev, tl);
1700 *tl++ = newnfs_false;
1701 txdr_hyper(tdirfor.na_filerev, tl);
1703 txdr_hyper(tdiraft.na_filerev, tl);
1707 NFSEXITCODE2(error, nd);
1715 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
1716 vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
1718 struct nameidata named;
1720 int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
1721 vnode_t dirp = NULL, dp = NULL;
1722 struct nfsvattr dirfor, diraft, at;
1723 struct nfsexstuff tnes;
1727 struct thread *p = curthread;
1729 if (nd->nd_repstat) {
1730 nfsrv_postopattr(nd, getret, &at);
1731 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1735 if (vnode_vtype(vp) == VDIR) {
1736 if (nd->nd_flag & ND_NFSV4)
1737 nd->nd_repstat = NFSERR_ISDIR;
1739 nd->nd_repstat = NFSERR_INVAL;
1743 if (!nd->nd_repstat) {
1744 if (nd->nd_flag & ND_NFSV4) {
1748 error = nfsrv_mtofh(nd, &dfh);
1751 /* tovp is always NULL unless NFSv4 */
1754 nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0);
1759 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1760 LOCKPARENT | SAVENAME | NOCACHE);
1761 if (!nd->nd_repstat) {
1762 nfsvno_setpathbuf(&named, &bufp, &hashp);
1763 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1768 nfsvno_relpathbuf(&named);
1771 if (!nd->nd_repstat) {
1772 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
1777 nfsvno_relpathbuf(&named);
1781 if (nd->nd_flag & ND_NFSV2) {
1785 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1789 if (!nd->nd_repstat)
1790 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
1791 if (nd->nd_flag & ND_NFSV3)
1792 getret = nfsvno_getattr(vp, &at, nd, p, 0, NULL);
1794 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1798 if (nd->nd_flag & ND_NFSV3) {
1799 nfsrv_postopattr(nd, getret, &at);
1800 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1801 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1802 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1803 *tl++ = newnfs_false;
1804 txdr_hyper(dirfor.na_filerev, tl);
1806 txdr_hyper(diraft.na_filerev, tl);
1810 NFSEXITCODE2(error, nd);
1815 * nfs symbolic link service
1818 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1819 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
1821 struct nfsvattr nva, dirfor, diraft;
1822 struct nameidata named;
1823 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1824 vnode_t dirp = NULL;
1825 char *bufp, *pathcp = NULL;
1827 struct thread *p = curthread;
1829 if (nd->nd_repstat) {
1830 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1835 NFSVNO_ATTRINIT(&nva);
1836 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1837 LOCKPARENT | SAVESTART | NOCACHE);
1838 nfsvno_setpathbuf(&named, &bufp, &hashp);
1839 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1840 if (!error && !nd->nd_repstat)
1841 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
1844 nfsvno_relpathbuf(&named);
1847 if (!nd->nd_repstat) {
1848 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1851 nfsvno_relpathbuf(&named);
1853 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1859 * And call nfsrvd_symlinksub() to do the common code. It will
1860 * return EBADRPC upon a parsing error, 0 otherwise.
1862 if (!nd->nd_repstat) {
1864 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1866 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1867 &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
1869 } else if (dirp != NULL) {
1870 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
1874 free(pathcp, M_TEMP);
1876 if (nd->nd_flag & ND_NFSV3) {
1877 if (!nd->nd_repstat) {
1878 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1879 nfsrv_postopattr(nd, 0, &nva);
1881 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1885 NFSEXITCODE2(error, nd);
1890 * Common code for creating a symbolic link.
1893 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
1894 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1895 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1896 int *diraft_retp, nfsattrbit_t *attrbitp,
1897 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
1902 nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
1903 !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
1904 if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
1905 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
1906 if (nd->nd_flag & ND_NFSV3) {
1907 nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
1908 if (!nd->nd_repstat)
1909 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
1910 nvap, nd, p, 1, NULL);
1912 if (vpp != NULL && nd->nd_repstat == 0) {
1913 NFSVOPUNLOCK(ndp->ni_vp);
1919 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL);
1922 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1923 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1924 *tl++ = newnfs_false;
1925 txdr_hyper(dirforp->na_filerev, tl);
1927 txdr_hyper(diraftp->na_filerev, tl);
1928 (void) nfsrv_putattrbit(nd, attrbitp);
1931 NFSEXITCODE2(0, nd);
1938 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
1939 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
1941 struct nfsvattr nva, dirfor, diraft;
1942 struct nameidata named;
1944 int error = 0, dirfor_ret = 1, diraft_ret = 1;
1945 vnode_t dirp = NULL;
1948 struct thread *p = curthread;
1950 if (nd->nd_repstat) {
1951 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1954 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1955 LOCKPARENT | SAVENAME | NOCACHE);
1956 nfsvno_setpathbuf(&named, &bufp, &hashp);
1957 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1960 if (!nd->nd_repstat) {
1961 NFSVNO_ATTRINIT(&nva);
1962 if (nd->nd_flag & ND_NFSV3) {
1963 error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
1967 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1968 nva.na_mode = nfstov_mode(*tl++);
1971 if (!nd->nd_repstat) {
1972 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1975 nfsvno_relpathbuf(&named);
1977 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1981 if (nd->nd_repstat) {
1983 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1987 if (nd->nd_flag & ND_NFSV3)
1988 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1993 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
1996 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
1998 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
1999 &diraft_ret, NULL, NULL, p, exp);
2001 if (nd->nd_flag & ND_NFSV3) {
2002 if (!nd->nd_repstat) {
2003 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
2004 nfsrv_postopattr(nd, 0, &nva);
2006 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
2007 } else if (!nd->nd_repstat) {
2008 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2009 nfsrv_fillattr(nd, &nva);
2013 NFSEXITCODE2(0, nd);
2017 nfsvno_relpathbuf(&named);
2018 NFSEXITCODE2(error, nd);
2023 * Code common to mkdir for V2,3 and 4.
2026 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
2027 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
2028 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
2029 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
2030 NFSPROC_T *p, struct nfsexstuff *exp)
2035 NFSVNO_SETATTRVAL(nvap, type, VDIR);
2036 nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
2037 nd->nd_cred, p, exp);
2038 if (!nd->nd_repstat) {
2040 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
2041 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
2042 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
2043 nd->nd_repstat = nfsvno_getattr(vp, nvap, nd, p, 1,
2045 if (vpp && !nd->nd_repstat) {
2053 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL);
2056 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
2057 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2058 *tl++ = newnfs_false;
2059 txdr_hyper(dirforp->na_filerev, tl);
2061 txdr_hyper(diraftp->na_filerev, tl);
2062 (void) nfsrv_putattrbit(nd, attrbitp);
2065 NFSEXITCODE2(0, nd);
2069 * nfs commit service
2072 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
2073 vnode_t vp, __unused struct nfsexstuff *exp)
2075 struct nfsvattr bfor, aft;
2077 int error = 0, for_ret = 1, aft_ret = 1, cnt;
2079 struct thread *p = curthread;
2081 if (nd->nd_repstat) {
2082 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
2086 /* Return NFSERR_ISDIR in NFSv4 when commit on a directory. */
2087 if (vp->v_type != VREG) {
2088 if (nd->nd_flag & ND_NFSV3)
2089 error = NFSERR_NOTSUPP;
2091 error = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_INVAL;
2094 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2097 * XXX At this time VOP_FSYNC() does not accept offset and byte
2098 * count parameters, so these arguments are useless (someday maybe).
2100 off = fxdr_hyper(tl);
2102 cnt = fxdr_unsigned(int, *tl);
2103 if (nd->nd_flag & ND_NFSV3)
2104 for_ret = nfsvno_getattr(vp, &bfor, nd, p, 1, NULL);
2105 nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
2106 if (nd->nd_flag & ND_NFSV3) {
2107 aft_ret = nfsvno_getattr(vp, &aft, nd, p, 1, NULL);
2108 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
2111 if (!nd->nd_repstat) {
2112 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2113 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
2114 *tl = txdr_unsigned(nfsboottime.tv_usec);
2118 NFSEXITCODE2(0, nd);
2122 NFSEXITCODE2(error, nd);
2127 * nfs statfs service
2130 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
2131 vnode_t vp, __unused struct nfsexstuff *exp)
2138 struct thread *p = curthread;
2141 if (nd->nd_repstat) {
2142 nfsrv_postopattr(nd, getret, &at);
2145 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2146 nd->nd_repstat = nfsvno_statfs(vp, sf);
2147 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2149 if (nd->nd_flag & ND_NFSV3)
2150 nfsrv_postopattr(nd, getret, &at);
2153 if (nd->nd_flag & ND_NFSV2) {
2154 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
2155 *tl++ = txdr_unsigned(NFS_V2MAXDATA);
2156 *tl++ = txdr_unsigned(sf->f_bsize);
2157 *tl++ = txdr_unsigned(sf->f_blocks);
2158 *tl++ = txdr_unsigned(sf->f_bfree);
2159 *tl = txdr_unsigned(sf->f_bavail);
2161 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
2162 tval = (u_quad_t)sf->f_blocks;
2163 tval *= (u_quad_t)sf->f_bsize;
2164 txdr_hyper(tval, tl); tl += 2;
2165 tval = (u_quad_t)sf->f_bfree;
2166 tval *= (u_quad_t)sf->f_bsize;
2167 txdr_hyper(tval, tl); tl += 2;
2168 tval = (u_quad_t)sf->f_bavail;
2169 tval *= (u_quad_t)sf->f_bsize;
2170 txdr_hyper(tval, tl); tl += 2;
2171 tval = (u_quad_t)sf->f_files;
2172 txdr_hyper(tval, tl); tl += 2;
2173 tval = (u_quad_t)sf->f_ffree;
2174 txdr_hyper(tval, tl); tl += 2;
2175 tval = (u_quad_t)sf->f_ffree;
2176 txdr_hyper(tval, tl); tl += 2;
2182 NFSEXITCODE2(0, nd);
2187 * nfs fsinfo service
2190 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
2191 vnode_t vp, __unused struct nfsexstuff *exp)
2194 struct nfsfsinfo fs;
2197 struct thread *p = curthread;
2199 if (nd->nd_repstat) {
2200 nfsrv_postopattr(nd, getret, &at);
2203 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2204 nfsvno_getfs(&fs, isdgram);
2206 nfsrv_postopattr(nd, getret, &at);
2207 NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
2208 *tl++ = txdr_unsigned(fs.fs_rtmax);
2209 *tl++ = txdr_unsigned(fs.fs_rtpref);
2210 *tl++ = txdr_unsigned(fs.fs_rtmult);
2211 *tl++ = txdr_unsigned(fs.fs_wtmax);
2212 *tl++ = txdr_unsigned(fs.fs_wtpref);
2213 *tl++ = txdr_unsigned(fs.fs_wtmult);
2214 *tl++ = txdr_unsigned(fs.fs_dtpref);
2215 txdr_hyper(fs.fs_maxfilesize, tl);
2217 txdr_nfsv3time(&fs.fs_timedelta, tl);
2219 *tl = txdr_unsigned(fs.fs_properties);
2222 NFSEXITCODE2(0, nd);
2227 * nfs pathconf service
2230 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
2231 vnode_t vp, __unused struct nfsexstuff *exp)
2233 struct nfsv3_pathconf *pc;
2235 long linkmax, namemax, chownres, notrunc;
2237 struct thread *p = curthread;
2239 if (nd->nd_repstat) {
2240 nfsrv_postopattr(nd, getret, &at);
2243 nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
2245 if (!nd->nd_repstat)
2246 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
2248 if (!nd->nd_repstat)
2249 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
2250 &chownres, nd->nd_cred, p);
2251 if (!nd->nd_repstat)
2252 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc,
2254 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2256 nfsrv_postopattr(nd, getret, &at);
2257 if (!nd->nd_repstat) {
2258 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
2259 pc->pc_linkmax = txdr_unsigned(linkmax);
2260 pc->pc_namemax = txdr_unsigned(namemax);
2261 pc->pc_notrunc = txdr_unsigned(notrunc);
2262 pc->pc_chownrestricted = txdr_unsigned(chownres);
2265 * These should probably be supported by VOP_PATHCONF(), but
2266 * until msdosfs is exportable (why would you want to?), the
2267 * Unix defaults should be ok.
2269 pc->pc_caseinsensitive = newnfs_false;
2270 pc->pc_casepreserving = newnfs_true;
2274 NFSEXITCODE2(0, nd);
2279 * nfsv4 lock service
2282 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2283 vnode_t vp, struct nfsexstuff *exp)
2287 struct nfsstate *stp = NULL;
2288 struct nfslock *lop;
2289 struct nfslockconflict cf;
2291 u_short flags = NFSLCK_LOCK, lflags;
2292 u_int64_t offset, len;
2293 nfsv4stateid_t stateid;
2295 struct thread *p = curthread;
2297 NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2298 i = fxdr_unsigned(int, *tl++);
2300 case NFSV4LOCKT_READW:
2301 flags |= NFSLCK_BLOCKING;
2302 case NFSV4LOCKT_READ:
2303 lflags = NFSLCK_READ;
2305 case NFSV4LOCKT_WRITEW:
2306 flags |= NFSLCK_BLOCKING;
2307 case NFSV4LOCKT_WRITE:
2308 lflags = NFSLCK_WRITE;
2311 nd->nd_repstat = NFSERR_BADXDR;
2314 if (*tl++ == newnfs_true)
2315 flags |= NFSLCK_RECLAIM;
2316 offset = fxdr_hyper(tl);
2318 len = fxdr_hyper(tl);
2320 if (*tl == newnfs_true)
2321 flags |= NFSLCK_OPENTOLOCK;
2322 if (flags & NFSLCK_OPENTOLOCK) {
2323 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2324 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2325 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2326 nd->nd_repstat = NFSERR_BADXDR;
2329 stp = malloc(sizeof (struct nfsstate) + i,
2330 M_NFSDSTATE, M_WAITOK);
2331 stp->ls_ownerlen = i;
2332 stp->ls_op = nd->nd_rp;
2333 stp->ls_seq = fxdr_unsigned(int, *tl++);
2334 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2335 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2337 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2340 * For the special stateid of other all 0s and seqid == 1, set
2341 * the stateid to the current stateid, if it is set.
2343 if ((nd->nd_flag & ND_NFSV41) != 0 &&
2344 stp->ls_stateid.seqid == 1 &&
2345 stp->ls_stateid.other[0] == 0 &&
2346 stp->ls_stateid.other[1] == 0 &&
2347 stp->ls_stateid.other[2] == 0) {
2348 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2349 stp->ls_stateid = nd->nd_curstateid;
2350 stp->ls_stateid.seqid = 0;
2352 nd->nd_repstat = NFSERR_BADSTATEID;
2357 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2358 clientid.lval[0] = *tl++;
2359 clientid.lval[1] = *tl++;
2360 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2361 if ((nd->nd_flag & ND_NFSV41) != 0)
2362 clientid.qval = nd->nd_clientid.qval;
2363 else if (nd->nd_clientid.qval != clientid.qval)
2364 printf("EEK3 multiple clids\n");
2366 if ((nd->nd_flag & ND_NFSV41) != 0)
2367 printf("EEK! no clientid from session\n");
2368 nd->nd_flag |= ND_IMPLIEDCLID;
2369 nd->nd_clientid.qval = clientid.qval;
2371 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2375 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2376 stp = malloc(sizeof (struct nfsstate),
2377 M_NFSDSTATE, M_WAITOK);
2378 stp->ls_ownerlen = 0;
2379 stp->ls_op = nd->nd_rp;
2380 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2381 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2383 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2386 * For the special stateid of other all 0s and seqid == 1, set
2387 * the stateid to the current stateid, if it is set.
2389 if ((nd->nd_flag & ND_NFSV41) != 0 &&
2390 stp->ls_stateid.seqid == 1 &&
2391 stp->ls_stateid.other[0] == 0 &&
2392 stp->ls_stateid.other[1] == 0 &&
2393 stp->ls_stateid.other[2] == 0) {
2394 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2395 stp->ls_stateid = nd->nd_curstateid;
2396 stp->ls_stateid.seqid = 0;
2398 nd->nd_repstat = NFSERR_BADSTATEID;
2403 stp->ls_seq = fxdr_unsigned(int, *tl);
2404 clientid.lval[0] = stp->ls_stateid.other[0];
2405 clientid.lval[1] = stp->ls_stateid.other[1];
2406 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2407 if ((nd->nd_flag & ND_NFSV41) != 0)
2408 clientid.qval = nd->nd_clientid.qval;
2409 else if (nd->nd_clientid.qval != clientid.qval)
2410 printf("EEK4 multiple clids\n");
2412 if ((nd->nd_flag & ND_NFSV41) != 0)
2413 printf("EEK! no clientid from session\n");
2414 nd->nd_flag |= ND_IMPLIEDCLID;
2415 nd->nd_clientid.qval = clientid.qval;
2418 lop = malloc(sizeof (struct nfslock),
2419 M_NFSDLOCK, M_WAITOK);
2420 lop->lo_first = offset;
2421 if (len == NFS64BITSSET) {
2422 lop->lo_end = NFS64BITSSET;
2424 lop->lo_end = offset + len;
2425 if (lop->lo_end <= lop->lo_first)
2426 nd->nd_repstat = NFSERR_INVAL;
2428 lop->lo_flags = lflags;
2429 stp->ls_flags = flags;
2430 stp->ls_uid = nd->nd_cred->cr_uid;
2433 * Do basic access checking.
2435 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2436 if (vnode_vtype(vp) == VDIR)
2437 nd->nd_repstat = NFSERR_ISDIR;
2439 nd->nd_repstat = NFSERR_INVAL;
2441 if (!nd->nd_repstat) {
2442 if (lflags & NFSLCK_WRITE) {
2443 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
2444 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2445 NFSACCCHK_VPISLOCKED, NULL);
2447 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
2448 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2449 NFSACCCHK_VPISLOCKED, NULL);
2451 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2452 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2453 NFSACCCHK_VPISLOCKED, NULL);
2458 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
2459 * seqid# gets updated. nfsrv_lockctrl() will return the value
2460 * of nd_repstat, if it gets that far.
2462 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2463 &stateid, exp, nd, p);
2465 free(lop, M_NFSDLOCK);
2467 free(stp, M_NFSDSTATE);
2468 if (!nd->nd_repstat) {
2469 /* For NFSv4.1, set the Current StateID. */
2470 if ((nd->nd_flag & ND_NFSV41) != 0) {
2471 nd->nd_curstateid = stateid;
2472 nd->nd_flag |= ND_CURSTATEID;
2474 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2475 *tl++ = txdr_unsigned(stateid.seqid);
2476 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2477 } else if (nd->nd_repstat == NFSERR_DENIED) {
2478 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2479 txdr_hyper(cf.cl_first, tl);
2481 if (cf.cl_end == NFS64BITSSET)
2484 len = cf.cl_end - cf.cl_first;
2485 txdr_hyper(len, tl);
2487 if (cf.cl_flags == NFSLCK_WRITE)
2488 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2490 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2491 *tl++ = stateid.other[0];
2492 *tl = stateid.other[1];
2493 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2496 NFSEXITCODE2(0, nd);
2501 free(stp, M_NFSDSTATE);
2502 NFSEXITCODE2(error, nd);
2507 * nfsv4 lock test service
2510 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2511 vnode_t vp, struct nfsexstuff *exp)
2515 struct nfsstate *stp = NULL;
2516 struct nfslock lo, *lop = &lo;
2517 struct nfslockconflict cf;
2519 nfsv4stateid_t stateid;
2522 struct thread *p = curthread;
2524 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2525 i = fxdr_unsigned(int, *(tl + 7));
2526 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2527 nd->nd_repstat = NFSERR_BADXDR;
2530 stp = malloc(sizeof (struct nfsstate) + i,
2531 M_NFSDSTATE, M_WAITOK);
2532 stp->ls_ownerlen = i;
2534 stp->ls_flags = NFSLCK_TEST;
2535 stp->ls_uid = nd->nd_cred->cr_uid;
2536 i = fxdr_unsigned(int, *tl++);
2538 case NFSV4LOCKT_READW:
2539 stp->ls_flags |= NFSLCK_BLOCKING;
2540 case NFSV4LOCKT_READ:
2541 lo.lo_flags = NFSLCK_READ;
2543 case NFSV4LOCKT_WRITEW:
2544 stp->ls_flags |= NFSLCK_BLOCKING;
2545 case NFSV4LOCKT_WRITE:
2546 lo.lo_flags = NFSLCK_WRITE;
2549 nd->nd_repstat = NFSERR_BADXDR;
2552 lo.lo_first = fxdr_hyper(tl);
2554 len = fxdr_hyper(tl);
2555 if (len == NFS64BITSSET) {
2556 lo.lo_end = NFS64BITSSET;
2558 lo.lo_end = lo.lo_first + len;
2559 if (lo.lo_end <= lo.lo_first)
2560 nd->nd_repstat = NFSERR_INVAL;
2563 clientid.lval[0] = *tl++;
2564 clientid.lval[1] = *tl;
2565 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2566 if ((nd->nd_flag & ND_NFSV41) != 0)
2567 clientid.qval = nd->nd_clientid.qval;
2568 else if (nd->nd_clientid.qval != clientid.qval)
2569 printf("EEK5 multiple clids\n");
2571 if ((nd->nd_flag & ND_NFSV41) != 0)
2572 printf("EEK! no clientid from session\n");
2573 nd->nd_flag |= ND_IMPLIEDCLID;
2574 nd->nd_clientid.qval = clientid.qval;
2576 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2579 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2580 if (vnode_vtype(vp) == VDIR)
2581 nd->nd_repstat = NFSERR_ISDIR;
2583 nd->nd_repstat = NFSERR_INVAL;
2585 if (!nd->nd_repstat)
2586 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2587 &stateid, exp, nd, p);
2588 if (nd->nd_repstat) {
2589 if (nd->nd_repstat == NFSERR_DENIED) {
2590 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2591 txdr_hyper(cf.cl_first, tl);
2593 if (cf.cl_end == NFS64BITSSET)
2596 len = cf.cl_end - cf.cl_first;
2597 txdr_hyper(len, tl);
2599 if (cf.cl_flags == NFSLCK_WRITE)
2600 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2602 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2603 *tl++ = stp->ls_stateid.other[0];
2604 *tl = stp->ls_stateid.other[1];
2605 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2610 free(stp, M_NFSDSTATE);
2611 NFSEXITCODE2(0, nd);
2616 free(stp, M_NFSDSTATE);
2617 NFSEXITCODE2(error, nd);
2622 * nfsv4 unlock service
2625 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2626 vnode_t vp, struct nfsexstuff *exp)
2630 struct nfsstate *stp;
2631 struct nfslock *lop;
2633 nfsv4stateid_t stateid;
2636 struct thread *p = curthread;
2638 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2639 stp = malloc(sizeof (struct nfsstate),
2640 M_NFSDSTATE, M_WAITOK);
2641 lop = malloc(sizeof (struct nfslock),
2642 M_NFSDLOCK, M_WAITOK);
2643 stp->ls_flags = NFSLCK_UNLOCK;
2644 lop->lo_flags = NFSLCK_UNLOCK;
2645 stp->ls_op = nd->nd_rp;
2646 i = fxdr_unsigned(int, *tl++);
2648 case NFSV4LOCKT_READW:
2649 stp->ls_flags |= NFSLCK_BLOCKING;
2650 case NFSV4LOCKT_READ:
2652 case NFSV4LOCKT_WRITEW:
2653 stp->ls_flags |= NFSLCK_BLOCKING;
2654 case NFSV4LOCKT_WRITE:
2657 nd->nd_repstat = NFSERR_BADXDR;
2658 free(stp, M_NFSDSTATE);
2659 free(lop, M_NFSDLOCK);
2662 stp->ls_ownerlen = 0;
2663 stp->ls_uid = nd->nd_cred->cr_uid;
2664 stp->ls_seq = fxdr_unsigned(int, *tl++);
2665 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2666 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2668 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2671 * For the special stateid of other all 0s and seqid == 1, set the
2672 * stateid to the current stateid, if it is set.
2674 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
2675 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
2676 stp->ls_stateid.other[2] == 0) {
2677 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2678 stp->ls_stateid = nd->nd_curstateid;
2679 stp->ls_stateid.seqid = 0;
2681 nd->nd_repstat = NFSERR_BADSTATEID;
2686 lop->lo_first = fxdr_hyper(tl);
2688 len = fxdr_hyper(tl);
2689 if (len == NFS64BITSSET) {
2690 lop->lo_end = NFS64BITSSET;
2692 lop->lo_end = lop->lo_first + len;
2693 if (lop->lo_end <= lop->lo_first)
2694 nd->nd_repstat = NFSERR_INVAL;
2696 clientid.lval[0] = stp->ls_stateid.other[0];
2697 clientid.lval[1] = stp->ls_stateid.other[1];
2698 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2699 if ((nd->nd_flag & ND_NFSV41) != 0)
2700 clientid.qval = nd->nd_clientid.qval;
2701 else if (nd->nd_clientid.qval != clientid.qval)
2702 printf("EEK6 multiple clids\n");
2704 if ((nd->nd_flag & ND_NFSV41) != 0)
2705 printf("EEK! no clientid from session\n");
2706 nd->nd_flag |= ND_IMPLIEDCLID;
2707 nd->nd_clientid.qval = clientid.qval;
2709 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2710 if (vnode_vtype(vp) == VDIR)
2711 nd->nd_repstat = NFSERR_ISDIR;
2713 nd->nd_repstat = NFSERR_INVAL;
2716 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2717 * seqid# gets incremented. nfsrv_lockctrl() will return the
2718 * value of nd_repstat, if it gets that far.
2720 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2721 &stateid, exp, nd, p);
2723 free(stp, M_NFSDSTATE);
2725 free(lop, M_NFSDLOCK);
2726 if (!nd->nd_repstat) {
2727 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2728 *tl++ = txdr_unsigned(stateid.seqid);
2729 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2733 NFSEXITCODE2(error, nd);
2738 * nfsv4 open service
2741 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2742 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, struct nfsexstuff *exp)
2746 struct nfsstate *stp = NULL;
2747 int error = 0, create, claim, exclusive_flag = 0, override;
2748 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2749 int how = NFSCREATE_UNCHECKED;
2750 int32_t cverf[2], tverf[2] = { 0, 0 };
2751 vnode_t vp = NULL, dirp = NULL;
2752 struct nfsvattr nva, dirfor, diraft;
2753 struct nameidata named;
2754 nfsv4stateid_t stateid, delegstateid;
2755 nfsattrbit_t attrbits;
2759 NFSACL_T *aclp = NULL;
2760 struct thread *p = curthread;
2762 #ifdef NFS4_ACL_EXTATTR_NAME
2763 aclp = acl_alloc(M_WAITOK);
2766 NFSZERO_ATTRBIT(&attrbits);
2767 named.ni_startdir = NULL;
2768 named.ni_cnd.cn_nameiop = 0;
2769 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2770 i = fxdr_unsigned(int, *(tl + 5));
2771 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2772 nd->nd_repstat = NFSERR_BADXDR;
2775 stp = malloc(sizeof (struct nfsstate) + i,
2776 M_NFSDSTATE, M_WAITOK);
2777 stp->ls_ownerlen = i;
2778 stp->ls_op = nd->nd_rp;
2779 stp->ls_flags = NFSLCK_OPEN;
2780 stp->ls_uid = nd->nd_cred->cr_uid;
2781 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2782 i = fxdr_unsigned(int, *tl++);
2784 if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG |
2785 NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) {
2787 /* For now, ignore these. */
2788 i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG);
2789 switch (i & NFSV4OPEN_WANTDELEGMASK) {
2790 case NFSV4OPEN_WANTANYDELEG:
2791 stp->ls_flags |= (NFSLCK_WANTRDELEG |
2793 i &= ~NFSV4OPEN_WANTDELEGMASK;
2795 case NFSV4OPEN_WANTREADDELEG:
2796 stp->ls_flags |= NFSLCK_WANTRDELEG;
2797 i &= ~NFSV4OPEN_WANTDELEGMASK;
2799 case NFSV4OPEN_WANTWRITEDELEG:
2800 stp->ls_flags |= NFSLCK_WANTWDELEG;
2801 i &= ~NFSV4OPEN_WANTDELEGMASK;
2803 case NFSV4OPEN_WANTNODELEG:
2804 stp->ls_flags |= NFSLCK_WANTNODELEG;
2805 i &= ~NFSV4OPEN_WANTDELEGMASK;
2807 case NFSV4OPEN_WANTCANCEL:
2808 printf("NFSv4: ignore Open WantCancel\n");
2809 i &= ~NFSV4OPEN_WANTDELEGMASK;
2812 /* nd_repstat will be set to NFSERR_INVAL below. */
2817 case NFSV4OPEN_ACCESSREAD:
2818 stp->ls_flags |= NFSLCK_READACCESS;
2820 case NFSV4OPEN_ACCESSWRITE:
2821 stp->ls_flags |= NFSLCK_WRITEACCESS;
2823 case NFSV4OPEN_ACCESSBOTH:
2824 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2827 nd->nd_repstat = NFSERR_INVAL;
2829 i = fxdr_unsigned(int, *tl++);
2831 case NFSV4OPEN_DENYNONE:
2833 case NFSV4OPEN_DENYREAD:
2834 stp->ls_flags |= NFSLCK_READDENY;
2836 case NFSV4OPEN_DENYWRITE:
2837 stp->ls_flags |= NFSLCK_WRITEDENY;
2839 case NFSV4OPEN_DENYBOTH:
2840 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
2843 nd->nd_repstat = NFSERR_INVAL;
2845 clientid.lval[0] = *tl++;
2846 clientid.lval[1] = *tl;
2847 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2848 if ((nd->nd_flag & ND_NFSV41) != 0)
2849 clientid.qval = nd->nd_clientid.qval;
2850 else if (nd->nd_clientid.qval != clientid.qval)
2851 printf("EEK7 multiple clids\n");
2853 if ((nd->nd_flag & ND_NFSV41) != 0)
2854 printf("EEK! no clientid from session\n");
2855 nd->nd_flag |= ND_IMPLIEDCLID;
2856 nd->nd_clientid.qval = clientid.qval;
2858 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2861 NFSVNO_ATTRINIT(&nva);
2862 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2863 create = fxdr_unsigned(int, *tl);
2864 if (!nd->nd_repstat)
2865 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
2866 if (create == NFSV4OPEN_CREATE) {
2869 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2870 how = fxdr_unsigned(int, *tl);
2872 case NFSCREATE_UNCHECKED:
2873 case NFSCREATE_GUARDED:
2874 error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
2878 * If the na_gid being set is the same as that of
2879 * the directory it is going in, clear it, since
2880 * that is what will be set by default. This allows
2881 * a user that isn't in that group to do the create.
2883 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
2884 nva.na_gid == dirfor.na_gid)
2885 NFSVNO_UNSET(&nva, gid);
2886 if (!nd->nd_repstat)
2887 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2889 case NFSCREATE_EXCLUSIVE:
2890 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2894 case NFSCREATE_EXCLUSIVE41:
2895 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2898 error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
2901 if (NFSISSET_ATTRBIT(&attrbits,
2902 NFSATTRBIT_TIMEACCESSSET))
2903 nd->nd_repstat = NFSERR_INVAL;
2905 * If the na_gid being set is the same as that of
2906 * the directory it is going in, clear it, since
2907 * that is what will be set by default. This allows
2908 * a user that isn't in that group to do the create.
2910 if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) &&
2911 nva.na_gid == dirfor.na_gid)
2912 NFSVNO_UNSET(&nva, gid);
2913 if (nd->nd_repstat == 0)
2914 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2917 nd->nd_repstat = NFSERR_BADXDR;
2920 } else if (create != NFSV4OPEN_NOCREATE) {
2921 nd->nd_repstat = NFSERR_BADXDR;
2926 * Now, handle the claim, which usually includes looking up a
2927 * name in the directory referenced by dp. The exception is
2928 * NFSV4OPEN_CLAIMPREVIOUS.
2930 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2931 claim = fxdr_unsigned(int, *tl);
2932 if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
2933 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2934 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2935 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
2936 stp->ls_flags |= NFSLCK_DELEGCUR;
2937 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2938 stp->ls_flags |= NFSLCK_DELEGPREV;
2940 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
2941 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2942 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
2943 claim != NFSV4OPEN_CLAIMNULL)
2944 nd->nd_repstat = NFSERR_INVAL;
2945 if (nd->nd_repstat) {
2946 nd->nd_repstat = nfsrv_opencheck(clientid,
2947 &stateid, stp, NULL, nd, p, nd->nd_repstat);
2950 if (create == NFSV4OPEN_CREATE)
2951 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
2952 LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
2954 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
2955 LOCKLEAF | SAVESTART);
2956 nfsvno_setpathbuf(&named, &bufp, &hashp);
2957 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2960 #ifdef NFS4_ACL_EXTATTR_NAME
2963 free(stp, M_NFSDSTATE);
2964 nfsvno_relpathbuf(&named);
2965 NFSEXITCODE2(error, nd);
2968 if (!nd->nd_repstat) {
2969 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
2973 nfsvno_relpathbuf(&named);
2975 if (create == NFSV4OPEN_CREATE) {
2977 case NFSCREATE_UNCHECKED:
2980 * Clear the setable attribute bits, except
2981 * for Size, if it is being truncated.
2983 NFSZERO_ATTRBIT(&attrbits);
2984 if (NFSVNO_ISSETSIZE(&nva))
2985 NFSSETBIT_ATTRBIT(&attrbits,
2989 case NFSCREATE_GUARDED:
2990 if (named.ni_vp && !nd->nd_repstat)
2991 nd->nd_repstat = EEXIST;
2993 case NFSCREATE_EXCLUSIVE:
2998 case NFSCREATE_EXCLUSIVE41:
3003 nfsvno_open(nd, &named, clientid, &stateid, stp,
3004 &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
3005 nd->nd_cred, exp, &vp);
3006 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim ==
3007 NFSV4OPEN_CLAIMFH) {
3008 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
3009 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3010 i = fxdr_unsigned(int, *tl);
3012 case NFSV4OPEN_DELEGATEREAD:
3013 stp->ls_flags |= NFSLCK_DELEGREAD;
3015 case NFSV4OPEN_DELEGATEWRITE:
3016 stp->ls_flags |= NFSLCK_DELEGWRITE;
3017 case NFSV4OPEN_DELEGATENONE:
3020 nd->nd_repstat = NFSERR_BADXDR;
3023 stp->ls_flags |= NFSLCK_RECLAIM;
3026 if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE)
3027 nd->nd_repstat = NFSERR_INVAL;
3030 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
3031 if (!VN_IS_DOOMED(vp))
3032 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
3033 stp, vp, nd, p, nd->nd_repstat);
3035 nd->nd_repstat = NFSERR_PERM;
3037 nd->nd_repstat = NFSERR_BADXDR;
3042 * Do basic access checking.
3044 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
3046 * The IETF working group decided that this is the correct
3047 * error return for all non-regular files.
3049 nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK;
3053 * If the Open is being done for a file that already exists, apply
3054 * normal permission checking including for the file owner, if
3055 * vfs.nfsd.v4openaccess is set.
3056 * Previously, the owner was always allowed to open the file to
3057 * be consistent with the NFS tradition of always allowing the
3058 * owner of the file to write to the file regardless of permissions.
3059 * It now appears that the Linux client expects the owner
3060 * permissions to be checked for opens that are not creating the
3061 * file. I believe the correct approach is to use the Access
3062 * operation's results to be consistent with NFSv3, but that is
3063 * not what the current Linux client appears to be doing.
3064 * Since both the Linux and OpenSolaris NFSv4 servers do this check,
3065 * I have enabled it by default.
3066 * If this semantic change causes a problem, it can be disabled by
3067 * setting the sysctl vfs.nfsd.v4openaccess to 0 to re-enable the
3068 * previous semantics.
3070 if (nfsrv_openaccess && create == NFSV4OPEN_NOCREATE)
3071 override = NFSACCCHK_NOOVERRIDE;
3073 override = NFSACCCHK_ALLOWOWNER;
3074 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
3075 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
3076 exp, p, override, NFSACCCHK_VPISLOCKED, NULL);
3077 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
3078 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
3079 exp, p, override, NFSACCCHK_VPISLOCKED, NULL);
3081 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
3082 nd->nd_cred, exp, p, override,
3083 NFSACCCHK_VPISLOCKED, NULL);
3086 if (!nd->nd_repstat) {
3087 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
3088 if (!nd->nd_repstat) {
3089 tverf[0] = nva.na_atime.tv_sec;
3090 tverf[1] = nva.na_atime.tv_nsec;
3093 if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
3094 cverf[1] != tverf[1]))
3095 nd->nd_repstat = EEXIST;
3097 * Do the open locking/delegation stuff.
3099 if (!nd->nd_repstat)
3100 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
3101 &delegstateid, &rflags, exp, p, nva.na_filerev);
3104 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
3105 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
3106 * (ie: Leave the NFSVOPUNLOCK() about here.)
3111 free(stp, M_NFSDSTATE);
3112 if (!nd->nd_repstat && dirp)
3113 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
3114 if (!nd->nd_repstat) {
3115 /* For NFSv4.1, set the Current StateID. */
3116 if ((nd->nd_flag & ND_NFSV41) != 0) {
3117 nd->nd_curstateid = stateid;
3118 nd->nd_flag |= ND_CURSTATEID;
3120 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
3121 *tl++ = txdr_unsigned(stateid.seqid);
3122 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3123 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3124 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
3125 *tl++ = newnfs_true;
3131 *tl++ = newnfs_false; /* Since dirp is not locked */
3132 txdr_hyper(dirfor.na_filerev, tl);
3134 txdr_hyper(diraft.na_filerev, tl);
3137 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
3138 (void) nfsrv_putattrbit(nd, &attrbits);
3139 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3140 if (rflags & NFSV4OPEN_READDELEGATE)
3141 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
3142 else if (rflags & NFSV4OPEN_WRITEDELEGATE)
3143 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
3144 else if (retext != 0) {
3145 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT);
3146 if ((rflags & NFSV4OPEN_WDNOTWANTED) != 0) {
3147 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3148 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
3149 } else if ((rflags & NFSV4OPEN_WDSUPPFTYPE) != 0) {
3150 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3151 *tl = txdr_unsigned(NFSV4OPEN_NOTSUPPFTYPE);
3152 } else if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) {
3153 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3154 *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION);
3156 } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) {
3157 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3158 *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE);
3161 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3162 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
3165 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
3166 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
3167 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
3168 *tl++ = txdr_unsigned(delegstateid.seqid);
3169 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
3171 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3172 if (rflags & NFSV4OPEN_RECALL)
3176 if (rflags & NFSV4OPEN_WRITEDELEGATE) {
3177 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3178 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
3179 txdr_hyper(nva.na_size, tl);
3181 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3182 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
3183 *tl++ = txdr_unsigned(0x0);
3184 acemask = NFSV4ACE_ALLFILESMASK;
3185 if (nva.na_mode & S_IRUSR)
3186 acemask |= NFSV4ACE_READMASK;
3187 if (nva.na_mode & S_IWUSR)
3188 acemask |= NFSV4ACE_WRITEMASK;
3189 if (nva.na_mode & S_IXUSR)
3190 acemask |= NFSV4ACE_EXECUTEMASK;
3191 *tl = txdr_unsigned(acemask);
3192 (void) nfsm_strtom(nd, "OWNER@", 6);
3200 #ifdef NFS4_ACL_EXTATTR_NAME
3203 NFSEXITCODE2(0, nd);
3207 #ifdef NFS4_ACL_EXTATTR_NAME
3211 free(stp, M_NFSDSTATE);
3212 NFSEXITCODE2(error, nd);
3217 * nfsv4 close service
3220 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
3221 vnode_t vp, __unused struct nfsexstuff *exp)
3224 struct nfsstate st, *stp = &st;
3225 int error = 0, writeacc;
3226 nfsv4stateid_t stateid;
3229 struct thread *p = curthread;
3231 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
3232 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3233 stp->ls_ownerlen = 0;
3234 stp->ls_op = nd->nd_rp;
3235 stp->ls_uid = nd->nd_cred->cr_uid;
3236 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3237 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3241 * For the special stateid of other all 0s and seqid == 1, set the
3242 * stateid to the current stateid, if it is set.
3244 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
3245 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
3246 stp->ls_stateid.other[2] == 0) {
3247 if ((nd->nd_flag & ND_CURSTATEID) != 0)
3248 stp->ls_stateid = nd->nd_curstateid;
3250 nd->nd_repstat = NFSERR_BADSTATEID;
3255 stp->ls_flags = NFSLCK_CLOSE;
3256 clientid.lval[0] = stp->ls_stateid.other[0];
3257 clientid.lval[1] = stp->ls_stateid.other[1];
3258 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3259 if ((nd->nd_flag & ND_NFSV41) != 0)
3260 clientid.qval = nd->nd_clientid.qval;
3261 else if (nd->nd_clientid.qval != clientid.qval)
3262 printf("EEK8 multiple clids\n");
3264 if ((nd->nd_flag & ND_NFSV41) != 0)
3265 printf("EEK! no clientid from session\n");
3266 nd->nd_flag |= ND_IMPLIEDCLID;
3267 nd->nd_clientid.qval = clientid.qval;
3269 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
3271 /* For pNFS, update the attributes. */
3272 if (writeacc != 0 || nfsrv_pnfsatime != 0)
3273 nfsrv_updatemdsattr(vp, &na, p);
3275 if (!nd->nd_repstat) {
3277 * If the stateid that has been closed is the current stateid,
3280 if ((nd->nd_flag & ND_CURSTATEID) != 0 &&
3281 stateid.other[0] == nd->nd_curstateid.other[0] &&
3282 stateid.other[1] == nd->nd_curstateid.other[1] &&
3283 stateid.other[2] == nd->nd_curstateid.other[2])
3284 nd->nd_flag &= ~ND_CURSTATEID;
3285 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3286 *tl++ = txdr_unsigned(stateid.seqid);
3287 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3289 NFSEXITCODE2(0, nd);
3293 NFSEXITCODE2(error, nd);
3298 * nfsv4 delegpurge service
3301 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
3302 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3307 struct thread *p = curthread;
3309 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3310 nd->nd_repstat = NFSERR_WRONGSEC;
3313 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3314 clientid.lval[0] = *tl++;
3315 clientid.lval[1] = *tl;
3316 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3317 if ((nd->nd_flag & ND_NFSV41) != 0)
3318 clientid.qval = nd->nd_clientid.qval;
3319 else if (nd->nd_clientid.qval != clientid.qval)
3320 printf("EEK9 multiple clids\n");
3322 if ((nd->nd_flag & ND_NFSV41) != 0)
3323 printf("EEK! no clientid from session\n");
3324 nd->nd_flag |= ND_IMPLIEDCLID;
3325 nd->nd_clientid.qval = clientid.qval;
3327 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL,
3328 NFSV4OP_DELEGPURGE, nd->nd_cred, p, NULL);
3330 NFSEXITCODE2(error, nd);
3335 * nfsv4 delegreturn service
3338 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
3339 vnode_t vp, __unused struct nfsexstuff *exp)
3342 int error = 0, writeacc;
3343 nfsv4stateid_t stateid;
3346 struct thread *p = curthread;
3348 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3349 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3350 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
3351 clientid.lval[0] = stateid.other[0];
3352 clientid.lval[1] = stateid.other[1];
3353 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3354 if ((nd->nd_flag & ND_NFSV41) != 0)
3355 clientid.qval = nd->nd_clientid.qval;
3356 else if (nd->nd_clientid.qval != clientid.qval)
3357 printf("EEK10 multiple clids\n");
3359 if ((nd->nd_flag & ND_NFSV41) != 0)
3360 printf("EEK! no clientid from session\n");
3361 nd->nd_flag |= ND_IMPLIEDCLID;
3362 nd->nd_clientid.qval = clientid.qval;
3364 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp,
3365 NFSV4OP_DELEGRETURN, nd->nd_cred, p, &writeacc);
3366 /* For pNFS, update the attributes. */
3367 if (writeacc != 0 || nfsrv_pnfsatime != 0)
3368 nfsrv_updatemdsattr(vp, &na, p);
3371 NFSEXITCODE2(error, nd);
3376 * nfsv4 get file handle service
3379 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
3380 vnode_t vp, __unused struct nfsexstuff *exp)
3383 struct thread *p = curthread;
3385 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3387 if (!nd->nd_repstat)
3388 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
3389 NFSEXITCODE2(0, nd);
3394 * nfsv4 open confirm service
3397 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
3398 vnode_t vp, __unused struct nfsexstuff *exp)
3401 struct nfsstate st, *stp = &st;
3403 nfsv4stateid_t stateid;
3405 struct thread *p = curthread;
3407 if ((nd->nd_flag & ND_NFSV41) != 0) {
3408 nd->nd_repstat = NFSERR_NOTSUPP;
3411 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
3412 stp->ls_ownerlen = 0;
3413 stp->ls_op = nd->nd_rp;
3414 stp->ls_uid = nd->nd_cred->cr_uid;
3415 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3416 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3418 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3419 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
3420 stp->ls_flags = NFSLCK_CONFIRM;
3421 clientid.lval[0] = stp->ls_stateid.other[0];
3422 clientid.lval[1] = stp->ls_stateid.other[1];
3423 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3424 if ((nd->nd_flag & ND_NFSV41) != 0)
3425 clientid.qval = nd->nd_clientid.qval;
3426 else if (nd->nd_clientid.qval != clientid.qval)
3427 printf("EEK11 multiple clids\n");
3429 if ((nd->nd_flag & ND_NFSV41) != 0)
3430 printf("EEK! no clientid from session\n");
3431 nd->nd_flag |= ND_IMPLIEDCLID;
3432 nd->nd_clientid.qval = clientid.qval;
3434 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
3436 if (!nd->nd_repstat) {
3437 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3438 *tl++ = txdr_unsigned(stateid.seqid);
3439 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3443 NFSEXITCODE2(error, nd);
3448 * nfsv4 open downgrade service
3451 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
3452 vnode_t vp, __unused struct nfsexstuff *exp)
3456 struct nfsstate st, *stp = &st;
3458 nfsv4stateid_t stateid;
3460 struct thread *p = curthread;
3462 /* opendowngrade can only work on a file object.*/
3463 if (vp->v_type != VREG) {
3464 error = NFSERR_INVAL;
3467 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
3468 stp->ls_ownerlen = 0;
3469 stp->ls_op = nd->nd_rp;
3470 stp->ls_uid = nd->nd_cred->cr_uid;
3471 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3472 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3474 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3477 * For the special stateid of other all 0s and seqid == 1, set the
3478 * stateid to the current stateid, if it is set.
3480 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
3481 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
3482 stp->ls_stateid.other[2] == 0) {
3483 if ((nd->nd_flag & ND_CURSTATEID) != 0)
3484 stp->ls_stateid = nd->nd_curstateid;
3486 nd->nd_repstat = NFSERR_BADSTATEID;
3491 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3492 i = fxdr_unsigned(int, *tl++);
3493 if ((nd->nd_flag & ND_NFSV41) != 0)
3494 i &= ~NFSV4OPEN_WANTDELEGMASK;
3496 case NFSV4OPEN_ACCESSREAD:
3497 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
3499 case NFSV4OPEN_ACCESSWRITE:
3500 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
3502 case NFSV4OPEN_ACCESSBOTH:
3503 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
3507 nd->nd_repstat = NFSERR_INVAL;
3509 i = fxdr_unsigned(int, *tl);
3511 case NFSV4OPEN_DENYNONE:
3513 case NFSV4OPEN_DENYREAD:
3514 stp->ls_flags |= NFSLCK_READDENY;
3516 case NFSV4OPEN_DENYWRITE:
3517 stp->ls_flags |= NFSLCK_WRITEDENY;
3519 case NFSV4OPEN_DENYBOTH:
3520 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3523 nd->nd_repstat = NFSERR_INVAL;
3526 clientid.lval[0] = stp->ls_stateid.other[0];
3527 clientid.lval[1] = stp->ls_stateid.other[1];
3528 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3529 if ((nd->nd_flag & ND_NFSV41) != 0)
3530 clientid.qval = nd->nd_clientid.qval;
3531 else if (nd->nd_clientid.qval != clientid.qval)
3532 printf("EEK12 multiple clids\n");
3534 if ((nd->nd_flag & ND_NFSV41) != 0)
3535 printf("EEK! no clientid from session\n");
3536 nd->nd_flag |= ND_IMPLIEDCLID;
3537 nd->nd_clientid.qval = clientid.qval;
3539 if (!nd->nd_repstat)
3540 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3542 if (!nd->nd_repstat) {
3543 /* For NFSv4.1, set the Current StateID. */
3544 if ((nd->nd_flag & ND_NFSV41) != 0) {
3545 nd->nd_curstateid = stateid;
3546 nd->nd_flag |= ND_CURSTATEID;
3548 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3549 *tl++ = txdr_unsigned(stateid.seqid);
3550 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3554 NFSEXITCODE2(error, nd);
3559 * nfsv4 renew lease service
3562 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3563 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3568 struct thread *p = curthread;
3570 if ((nd->nd_flag & ND_NFSV41) != 0) {
3571 nd->nd_repstat = NFSERR_NOTSUPP;
3574 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3575 nd->nd_repstat = NFSERR_WRONGSEC;
3578 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3579 clientid.lval[0] = *tl++;
3580 clientid.lval[1] = *tl;
3581 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3582 if ((nd->nd_flag & ND_NFSV41) != 0)
3583 clientid.qval = nd->nd_clientid.qval;
3584 else if (nd->nd_clientid.qval != clientid.qval)
3585 printf("EEK13 multiple clids\n");
3587 if ((nd->nd_flag & ND_NFSV41) != 0)
3588 printf("EEK! no clientid from session\n");
3589 nd->nd_flag |= ND_IMPLIEDCLID;
3590 nd->nd_clientid.qval = clientid.qval;
3592 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3593 NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p);
3595 NFSEXITCODE2(error, nd);
3600 * nfsv4 security info service
3603 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3604 vnode_t dp, struct nfsexstuff *exp)
3608 struct nameidata named;
3609 vnode_t dirp = NULL, vp;
3611 struct nfsexstuff retnes;
3613 int error = 0, savflag, i;
3616 struct thread *p = curthread;
3619 * All this just to get the export flags for the name.
3621 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3622 LOCKLEAF | SAVESTART);
3623 nfsvno_setpathbuf(&named, &bufp, &hashp);
3624 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3627 nfsvno_relpathbuf(&named);
3630 if (!nd->nd_repstat) {
3631 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
3634 nfsvno_relpathbuf(&named);
3640 vrele(named.ni_startdir);
3641 nfsvno_relpathbuf(&named);
3642 fh.nfsrvfh_len = NFSX_MYFH;
3644 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3646 savflag = nd->nd_flag;
3647 if (!nd->nd_repstat) {
3648 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0);
3652 nd->nd_flag = savflag;
3657 * Finally have the export flags for name, so we can create
3658 * the security info.
3661 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3662 for (i = 0; i < retnes.nes_numsecflavor; i++) {
3663 if (retnes.nes_secflavors[i] == AUTH_SYS) {
3664 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3665 *tl = txdr_unsigned(RPCAUTH_UNIX);
3667 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3668 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3669 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3670 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3671 nfsgss_mechlist[KERBV_MECH].len);
3672 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3673 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3674 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3676 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3677 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3678 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3679 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3680 nfsgss_mechlist[KERBV_MECH].len);
3681 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3682 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3683 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3685 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3686 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3687 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3688 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3689 nfsgss_mechlist[KERBV_MECH].len);
3690 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3691 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3692 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3696 *sizp = txdr_unsigned(len);
3699 NFSEXITCODE2(error, nd);
3704 * nfsv4 set client id service
3707 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3708 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3712 int error = 0, idlen;
3713 struct nfsclient *clp = NULL;
3715 struct sockaddr_in *rin;
3718 struct sockaddr_in6 *rin6;
3720 #if defined(INET) || defined(INET6)
3723 u_char *verf, *addrbuf;
3724 nfsquad_t clientid, confirm;
3725 struct thread *p = curthread;
3727 if ((nd->nd_flag & ND_NFSV41) != 0) {
3728 nd->nd_repstat = NFSERR_NOTSUPP;
3731 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3732 nd->nd_repstat = NFSERR_WRONGSEC;
3735 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3736 verf = (u_char *)tl;
3737 tl += (NFSX_VERF / NFSX_UNSIGNED);
3738 i = fxdr_unsigned(int, *tl);
3739 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3740 nd->nd_repstat = NFSERR_BADXDR;
3744 if (nd->nd_flag & ND_GSS)
3745 i += nd->nd_princlen;
3746 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
3748 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
3749 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
3750 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3751 /* Allocated large enough for an AF_INET or AF_INET6 socket. */
3752 clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
3754 clp->lc_req.nr_cred = NULL;
3755 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3756 clp->lc_idlen = idlen;
3757 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3760 if (nd->nd_flag & ND_GSS) {
3761 clp->lc_flags = LCL_GSS;
3762 if (nd->nd_flag & ND_GSSINTEGRITY)
3763 clp->lc_flags |= LCL_GSSINTEGRITY;
3764 else if (nd->nd_flag & ND_GSSPRIVACY)
3765 clp->lc_flags |= LCL_GSSPRIVACY;
3769 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
3770 clp->lc_flags |= LCL_NAME;
3771 clp->lc_namelen = nd->nd_princlen;
3772 clp->lc_name = &clp->lc_id[idlen];
3773 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3775 clp->lc_uid = nd->nd_cred->cr_uid;
3776 clp->lc_gid = nd->nd_cred->cr_gid;
3778 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3779 clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
3780 error = nfsrv_getclientipaddr(nd, clp);
3783 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3784 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
3787 * nfsrv_setclient() does the actual work of adding it to the
3788 * client list. If there is no error, the structure has been
3789 * linked into the client list and clp should no longer be used
3790 * here. When an error is returned, it has not been linked in,
3791 * so it should be free'd.
3793 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3794 if (nd->nd_repstat == NFSERR_CLIDINUSE) {
3796 * 8 is the maximum length of the port# string.
3798 addrbuf = malloc(INET6_ADDRSTRLEN + 8, M_TEMP, M_WAITOK);
3799 switch (clp->lc_req.nr_nam->sa_family) {
3802 if (clp->lc_flags & LCL_TCPCALLBACK)
3803 (void) nfsm_strtom(nd, "tcp", 3);
3805 (void) nfsm_strtom(nd, "udp", 3);
3806 rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
3807 ucp = (u_char *)&rin->sin_addr.s_addr;
3808 ucp2 = (u_char *)&rin->sin_port;
3809 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
3810 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
3811 ucp2[0] & 0xff, ucp2[1] & 0xff);
3816 if (clp->lc_flags & LCL_TCPCALLBACK)
3817 (void) nfsm_strtom(nd, "tcp6", 4);
3819 (void) nfsm_strtom(nd, "udp6", 4);
3820 rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
3821 ucp = inet_ntop(AF_INET6, &rin6->sin6_addr, addrbuf,
3827 ucp2 = (u_char *)&rin6->sin6_port;
3828 sprintf(&addrbuf[i], ".%d.%d", ucp2[0] & 0xff,
3833 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
3834 free(addrbuf, M_TEMP);
3837 free(clp->lc_req.nr_nam, M_SONAME);
3838 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3839 free(clp->lc_stateid, M_NFSDCLIENT);
3840 free(clp, M_NFSDCLIENT);
3842 if (!nd->nd_repstat) {
3843 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
3844 *tl++ = clientid.lval[0];
3845 *tl++ = clientid.lval[1];
3846 *tl++ = confirm.lval[0];
3847 *tl = confirm.lval[1];
3851 NFSEXITCODE2(0, nd);
3855 free(clp->lc_req.nr_nam, M_SONAME);
3856 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3857 free(clp->lc_stateid, M_NFSDCLIENT);
3858 free(clp, M_NFSDCLIENT);
3860 NFSEXITCODE2(error, nd);
3865 * nfsv4 set client id confirm service
3868 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
3869 __unused int isdgram, __unused vnode_t vp,
3870 __unused struct nfsexstuff *exp)
3874 nfsquad_t clientid, confirm;
3875 struct thread *p = curthread;
3877 if ((nd->nd_flag & ND_NFSV41) != 0) {
3878 nd->nd_repstat = NFSERR_NOTSUPP;
3881 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3882 nd->nd_repstat = NFSERR_WRONGSEC;
3885 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
3886 clientid.lval[0] = *tl++;
3887 clientid.lval[1] = *tl++;
3888 confirm.lval[0] = *tl++;
3889 confirm.lval[1] = *tl;
3892 * nfsrv_getclient() searches the client list for a match and
3893 * returns the appropriate NFSERR status.
3895 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
3896 NULL, NULL, confirm, 0, nd, p);
3898 NFSEXITCODE2(error, nd);
3903 * nfsv4 verify service
3906 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
3907 vnode_t vp, __unused struct nfsexstuff *exp)
3909 int error = 0, ret, fhsize = NFSX_MYFH;
3910 struct nfsvattr nva;
3912 struct nfsfsinfo fs;
3914 struct thread *p = curthread;
3916 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
3917 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
3918 if (!nd->nd_repstat)
3919 nd->nd_repstat = nfsvno_statfs(vp, sf);
3920 if (!nd->nd_repstat)
3921 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3922 if (!nd->nd_repstat) {
3923 nfsvno_getfs(&fs, isdgram);
3924 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
3925 sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
3927 if (nd->nd_procnum == NFSV4OP_NVERIFY) {
3929 nd->nd_repstat = NFSERR_SAME;
3930 else if (ret != NFSERR_NOTSAME)
3931 nd->nd_repstat = ret;
3933 nd->nd_repstat = ret;
3938 NFSEXITCODE2(error, nd);
3946 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
3947 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
3948 __unused struct nfsexstuff *exp)
3951 int error = 0, createdir __unused;
3953 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3954 createdir = fxdr_unsigned(int, *tl);
3955 nd->nd_repstat = NFSERR_NOTSUPP;
3958 NFSEXITCODE2(error, nd);
3963 * nfsv4 release lock owner service
3966 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
3967 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3970 struct nfsstate *stp = NULL;
3973 struct thread *p = curthread;
3975 if ((nd->nd_flag & ND_NFSV41) != 0) {
3976 nd->nd_repstat = NFSERR_NOTSUPP;
3979 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3980 nd->nd_repstat = NFSERR_WRONGSEC;
3983 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3984 len = fxdr_unsigned(int, *(tl + 2));
3985 if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
3986 nd->nd_repstat = NFSERR_BADXDR;
3989 stp = malloc(sizeof (struct nfsstate) + len,
3990 M_NFSDSTATE, M_WAITOK);
3991 stp->ls_ownerlen = len;
3993 stp->ls_flags = NFSLCK_RELEASE;
3994 stp->ls_uid = nd->nd_cred->cr_uid;
3995 clientid.lval[0] = *tl++;
3996 clientid.lval[1] = *tl;
3997 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3998 if ((nd->nd_flag & ND_NFSV41) != 0)
3999 clientid.qval = nd->nd_clientid.qval;
4000 else if (nd->nd_clientid.qval != clientid.qval)
4001 printf("EEK14 multiple clids\n");
4003 if ((nd->nd_flag & ND_NFSV41) != 0)
4004 printf("EEK! no clientid from session\n");
4005 nd->nd_flag |= ND_IMPLIEDCLID;
4006 nd->nd_clientid.qval = clientid.qval;
4008 error = nfsrv_mtostr(nd, stp->ls_owner, len);
4011 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
4012 free(stp, M_NFSDSTATE);
4014 NFSEXITCODE2(0, nd);
4018 free(stp, M_NFSDSTATE);
4019 NFSEXITCODE2(error, nd);
4024 * nfsv4 exchange_id service
4027 nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram,
4028 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4031 int error = 0, i, idlen;
4032 struct nfsclient *clp = NULL;
4033 nfsquad_t clientid, confirm;
4035 uint32_t sp4type, v41flags;
4036 uint64_t owner_minor;
4037 struct timespec verstime;
4039 struct sockaddr_in *sin, *rin;
4042 struct sockaddr_in6 *sin6, *rin6;
4044 struct thread *p = curthread;
4046 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4047 nd->nd_repstat = NFSERR_WRONGSEC;
4050 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
4051 verf = (uint8_t *)tl;
4052 tl += (NFSX_VERF / NFSX_UNSIGNED);
4053 i = fxdr_unsigned(int, *tl);
4054 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
4055 nd->nd_repstat = NFSERR_BADXDR;
4059 if (nd->nd_flag & ND_GSS)
4060 i += nd->nd_princlen;
4061 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
4063 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
4064 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
4065 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
4066 /* Allocated large enough for an AF_INET or AF_INET6 socket. */
4067 clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
4069 switch (nd->nd_nam->sa_family) {
4072 rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
4073 sin = (struct sockaddr_in *)nd->nd_nam;
4074 rin->sin_family = AF_INET;
4075 rin->sin_len = sizeof(struct sockaddr_in);
4077 rin->sin_addr.s_addr = sin->sin_addr.s_addr;
4082 rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
4083 sin6 = (struct sockaddr_in6 *)nd->nd_nam;
4084 rin6->sin6_family = AF_INET6;
4085 rin6->sin6_len = sizeof(struct sockaddr_in6);
4086 rin6->sin6_port = 0;
4087 rin6->sin6_addr = sin6->sin6_addr;
4091 clp->lc_req.nr_cred = NULL;
4092 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
4093 clp->lc_idlen = idlen;
4094 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
4097 if ((nd->nd_flag & ND_GSS) != 0) {
4098 clp->lc_flags = LCL_GSS | LCL_NFSV41;
4099 if ((nd->nd_flag & ND_GSSINTEGRITY) != 0)
4100 clp->lc_flags |= LCL_GSSINTEGRITY;
4101 else if ((nd->nd_flag & ND_GSSPRIVACY) != 0)
4102 clp->lc_flags |= LCL_GSSPRIVACY;
4104 clp->lc_flags = LCL_NFSV41;
4105 if ((nd->nd_flag & ND_NFSV42) != 0)
4106 clp->lc_flags |= LCL_NFSV42;
4107 if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) {
4108 clp->lc_flags |= LCL_NAME;
4109 clp->lc_namelen = nd->nd_princlen;
4110 clp->lc_name = &clp->lc_id[idlen];
4111 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
4113 clp->lc_uid = nd->nd_cred->cr_uid;
4114 clp->lc_gid = nd->nd_cred->cr_gid;
4116 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4117 v41flags = fxdr_unsigned(uint32_t, *tl++);
4118 if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR |
4119 NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS |
4120 NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) {
4121 nd->nd_repstat = NFSERR_INVAL;
4124 if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0)
4125 confirm.lval[1] = 1;
4127 confirm.lval[1] = 0;
4128 if (nfsrv_devidcnt == 0)
4129 v41flags = NFSV4EXCH_USENONPNFS | NFSV4EXCH_USEPNFSDS;
4131 v41flags = NFSV4EXCH_USEPNFSMDS;
4132 sp4type = fxdr_unsigned(uint32_t, *tl);
4133 if (sp4type != NFSV4EXCH_SP4NONE) {
4134 nd->nd_repstat = NFSERR_NOTSUPP;
4139 * nfsrv_setclient() does the actual work of adding it to the
4140 * client list. If there is no error, the structure has been
4141 * linked into the client list and clp should no longer be used
4142 * here. When an error is returned, it has not been linked in,
4143 * so it should be free'd.
4145 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
4147 free(clp->lc_req.nr_nam, M_SONAME);
4148 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4149 free(clp->lc_stateid, M_NFSDCLIENT);
4150 free(clp, M_NFSDCLIENT);
4152 if (nd->nd_repstat == 0) {
4153 if (confirm.lval[1] != 0)
4154 v41flags |= NFSV4EXCH_CONFIRMEDR;
4155 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED);
4156 *tl++ = clientid.lval[0]; /* ClientID */
4157 *tl++ = clientid.lval[1];
4158 *tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */
4159 *tl++ = txdr_unsigned(v41flags); /* Exch flags */
4160 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); /* No SSV */
4161 owner_minor = 0; /* Owner */
4162 txdr_hyper(owner_minor, tl); /* Minor */
4163 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid,
4164 strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */
4165 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid,
4166 strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Scope */
4167 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4168 *tl = txdr_unsigned(1);
4169 (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
4170 (void)nfsm_strtom(nd, version, strlen(version));
4171 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
4172 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */
4173 verstime.tv_nsec = 0;
4174 txdr_nfsv4time(&verstime, tl);
4176 NFSEXITCODE2(0, nd);
4180 free(clp->lc_req.nr_nam, M_SONAME);
4181 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4182 free(clp->lc_stateid, M_NFSDCLIENT);
4183 free(clp, M_NFSDCLIENT);
4185 NFSEXITCODE2(error, nd);
4190 * nfsv4 create session service
4193 nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram,
4194 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4198 nfsquad_t clientid, confirm;
4199 struct nfsdsession *sep = NULL;
4201 struct thread *p = curthread;
4203 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4204 nd->nd_repstat = NFSERR_WRONGSEC;
4207 sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession),
4208 M_NFSDSESSION, M_WAITOK | M_ZERO);
4209 sep->sess_refcnt = 1;
4210 mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF);
4211 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
4212 clientid.lval[0] = *tl++;
4213 clientid.lval[1] = *tl++;
4214 confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++);
4215 sep->sess_crflags = fxdr_unsigned(uint32_t, *tl);
4216 /* Persistent sessions and RDMA are not supported. */
4217 sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN;
4219 /* Fore channel attributes. */
4220 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4221 tl++; /* Header pad always 0. */
4222 sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++);
4223 if (sep->sess_maxreq > sb_max_adj - NFS_MAXXDR) {
4224 sep->sess_maxreq = sb_max_adj - NFS_MAXXDR;
4225 printf("Consider increasing kern.ipc.maxsockbuf\n");
4227 sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++);
4228 if (sep->sess_maxresp > sb_max_adj - NFS_MAXXDR) {
4229 sep->sess_maxresp = sb_max_adj - NFS_MAXXDR;
4230 printf("Consider increasing kern.ipc.maxsockbuf\n");
4232 sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++);
4233 sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++);
4234 sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++);
4235 if (sep->sess_maxslots > NFSV4_SLOTS)
4236 sep->sess_maxslots = NFSV4_SLOTS;
4237 rdmacnt = fxdr_unsigned(uint32_t, *tl);
4239 nd->nd_repstat = NFSERR_BADXDR;
4241 } else if (rdmacnt == 1)
4242 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4244 /* Back channel attributes. */
4245 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4246 tl++; /* Header pad always 0. */
4247 sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++);
4248 sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++);
4249 sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++);
4250 sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++);
4251 sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++);
4252 rdmacnt = fxdr_unsigned(uint32_t, *tl);
4254 nd->nd_repstat = NFSERR_BADXDR;
4256 } else if (rdmacnt == 1)
4257 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4259 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4260 sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl);
4263 * nfsrv_getclient() searches the client list for a match and
4264 * returns the appropriate NFSERR status.
4266 nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW,
4267 NULL, sep, confirm, sep->sess_cbprogram, nd, p);
4268 if (nd->nd_repstat == 0) {
4269 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4270 NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID);
4271 NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED);
4272 *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */
4273 *tl++ = txdr_unsigned(sep->sess_crflags);
4275 /* Fore channel attributes. */
4277 *tl++ = txdr_unsigned(sep->sess_maxreq);
4278 *tl++ = txdr_unsigned(sep->sess_maxresp);
4279 *tl++ = txdr_unsigned(sep->sess_maxrespcached);
4280 *tl++ = txdr_unsigned(sep->sess_maxops);
4281 *tl++ = txdr_unsigned(sep->sess_maxslots);
4282 *tl++ = txdr_unsigned(1);
4283 *tl++ = txdr_unsigned(0); /* No RDMA. */
4285 /* Back channel attributes. */
4287 *tl++ = txdr_unsigned(sep->sess_cbmaxreq);
4288 *tl++ = txdr_unsigned(sep->sess_cbmaxresp);
4289 *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached);
4290 *tl++ = txdr_unsigned(sep->sess_cbmaxops);
4291 *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots);
4292 *tl++ = txdr_unsigned(1);
4293 *tl = txdr_unsigned(0); /* No RDMA. */
4296 if (nd->nd_repstat != 0 && sep != NULL)
4297 free(sep, M_NFSDSESSION);
4298 NFSEXITCODE2(error, nd);
4303 * nfsv4 sequence service
4306 nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram,
4307 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4310 uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid;
4311 int cache_this, error = 0;
4312 struct thread *p = curthread;
4314 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4315 nd->nd_repstat = NFSERR_WRONGSEC;
4318 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID);
4319 NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID);
4320 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4321 sequenceid = fxdr_unsigned(uint32_t, *tl++);
4322 nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++);
4323 highest_slotid = fxdr_unsigned(uint32_t, *tl++);
4324 if (*tl == newnfs_true)
4328 nd->nd_flag |= ND_HASSEQUENCE;
4329 nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid,
4330 &target_highest_slotid, cache_this, &sflags, p);
4331 if (nd->nd_repstat == 0) {
4332 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4333 NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID);
4334 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
4335 *tl++ = txdr_unsigned(sequenceid);
4336 *tl++ = txdr_unsigned(nd->nd_slotid);
4337 *tl++ = txdr_unsigned(highest_slotid);
4338 *tl++ = txdr_unsigned(target_highest_slotid);
4339 *tl = txdr_unsigned(sflags);
4342 NFSEXITCODE2(error, nd);
4347 * nfsv4 reclaim complete service
4350 nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram,
4351 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4354 int error = 0, onefs;
4356 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4357 nd->nd_repstat = NFSERR_WRONGSEC;
4360 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4362 * I believe that a ReclaimComplete with rca_one_fs == TRUE is only
4363 * to be used after a file system has been transferred to a different
4364 * file server. However, RFC5661 is somewhat vague w.r.t. this and
4365 * the ESXi 6.7 client does both a ReclaimComplete with rca_one_fs
4366 * == TRUE and one with ReclaimComplete with rca_one_fs == FALSE.
4367 * Therefore, just ignore the rca_one_fs == TRUE operation and return
4368 * NFS_OK without doing anything.
4371 if (*tl == newnfs_true)
4373 nd->nd_repstat = nfsrv_checkreclaimcomplete(nd, onefs);
4375 NFSEXITCODE2(error, nd);
4380 * nfsv4 destroy clientid service
4383 nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram,
4384 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4389 struct thread *p = curthread;
4391 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4392 nd->nd_repstat = NFSERR_WRONGSEC;
4395 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4396 clientid.lval[0] = *tl++;
4397 clientid.lval[1] = *tl;
4398 nd->nd_repstat = nfsrv_destroyclient(clientid, p);
4400 NFSEXITCODE2(error, nd);
4405 * nfsv4 bind connection to session service
4408 nfsrvd_bindconnsess(struct nfsrv_descript *nd, __unused int isdgram,
4409 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4412 uint8_t sessid[NFSX_V4SESSIONID];
4413 int error = 0, foreaft;
4415 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4416 nd->nd_repstat = NFSERR_WRONGSEC;
4419 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED);
4420 NFSBCOPY(tl, sessid, NFSX_V4SESSIONID);
4421 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
4422 foreaft = fxdr_unsigned(int, *tl++);
4423 if (*tl == newnfs_true) {
4424 /* RDMA is not supported. */
4425 nd->nd_repstat = NFSERR_NOTSUPP;
4429 nd->nd_repstat = nfsrv_bindconnsess(nd, sessid, &foreaft);
4430 if (nd->nd_repstat == 0) {
4431 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 *
4433 NFSBCOPY(sessid, tl, NFSX_V4SESSIONID);
4434 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
4435 *tl++ = txdr_unsigned(foreaft);
4439 NFSEXITCODE2(error, nd);
4444 * nfsv4 destroy session service
4447 nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram,
4448 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4450 uint8_t *cp, sessid[NFSX_V4SESSIONID];
4453 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4454 nd->nd_repstat = NFSERR_WRONGSEC;
4457 NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID);
4458 NFSBCOPY(cp, sessid, NFSX_V4SESSIONID);
4459 nd->nd_repstat = nfsrv_destroysession(nd, sessid);
4461 NFSEXITCODE2(error, nd);
4466 * nfsv4 free stateid service
4469 nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram,
4470 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4473 nfsv4stateid_t stateid;
4475 struct thread *p = curthread;
4477 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4478 nd->nd_repstat = NFSERR_WRONGSEC;
4481 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
4482 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4483 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4486 * For the special stateid of other all 0s and seqid == 1, set the
4487 * stateid to the current stateid, if it is set.
4489 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4490 stateid.other[1] == 0 && stateid.other[2] == 0) {
4491 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4492 stateid = nd->nd_curstateid;
4495 nd->nd_repstat = NFSERR_BADSTATEID;
4500 nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p);
4502 /* If the current stateid has been free'd, unset it. */
4503 if (nd->nd_repstat == 0 && (nd->nd_flag & ND_CURSTATEID) != 0 &&
4504 stateid.other[0] == nd->nd_curstateid.other[0] &&
4505 stateid.other[1] == nd->nd_curstateid.other[1] &&
4506 stateid.other[2] == nd->nd_curstateid.other[2])
4507 nd->nd_flag &= ~ND_CURSTATEID;
4509 NFSEXITCODE2(error, nd);
4514 * nfsv4 layoutget service
4517 nfsrvd_layoutget(struct nfsrv_descript *nd, __unused int isdgram,
4518 vnode_t vp, struct nfsexstuff *exp)
4521 nfsv4stateid_t stateid;
4522 int error = 0, layoutlen, layouttype, iomode, maxcnt, retonclose;
4523 uint64_t offset, len, minlen;
4525 struct thread *p = curthread;
4527 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4528 nd->nd_repstat = NFSERR_WRONGSEC;
4531 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
4533 tl++; /* Signal layout available. Ignore for now. */
4534 layouttype = fxdr_unsigned(int, *tl++);
4535 iomode = fxdr_unsigned(int, *tl++);
4536 offset = fxdr_hyper(tl); tl += 2;
4537 len = fxdr_hyper(tl); tl += 2;
4538 minlen = fxdr_hyper(tl); tl += 2;
4539 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4540 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4541 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4542 maxcnt = fxdr_unsigned(int, *tl);
4543 NFSD_DEBUG(4, "layoutget ltyp=%d iom=%d off=%ju len=%ju mlen=%ju\n",
4544 layouttype, iomode, (uintmax_t)offset, (uintmax_t)len,
4547 (minlen != UINT64_MAX && offset + minlen < offset) ||
4548 (len != UINT64_MAX && offset + len < offset)) {
4549 nd->nd_repstat = NFSERR_INVAL;
4554 * For the special stateid of other all 0s and seqid == 1, set the
4555 * stateid to the current stateid, if it is set.
4557 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4558 stateid.other[1] == 0 && stateid.other[2] == 0) {
4559 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4560 stateid = nd->nd_curstateid;
4563 nd->nd_repstat = NFSERR_BADSTATEID;
4569 if (layouttype == NFSLAYOUT_NFSV4_1_FILES && nfsrv_maxpnfsmirror == 1)
4570 layp = malloc(NFSX_V4FILELAYOUT, M_TEMP, M_WAITOK);
4571 else if (layouttype == NFSLAYOUT_FLEXFILE)
4572 layp = malloc(NFSX_V4FLEXLAYOUT(nfsrv_maxpnfsmirror), M_TEMP,
4575 nd->nd_repstat = NFSERR_UNKNLAYOUTTYPE;
4577 nd->nd_repstat = nfsrv_layoutget(nd, vp, exp, layouttype,
4578 &iomode, &offset, &len, minlen, &stateid, maxcnt,
4579 &retonclose, &layoutlen, layp, nd->nd_cred, p);
4580 NFSD_DEBUG(4, "nfsrv_layoutget stat=%u layoutlen=%d\n", nd->nd_repstat,
4582 if (nd->nd_repstat == 0) {
4583 /* For NFSv4.1, set the Current StateID. */
4584 if ((nd->nd_flag & ND_NFSV41) != 0) {
4585 nd->nd_curstateid = stateid;
4586 nd->nd_flag |= ND_CURSTATEID;
4588 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_STATEID +
4590 *tl++ = txdr_unsigned(retonclose);
4591 *tl++ = txdr_unsigned(stateid.seqid);
4592 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
4593 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4594 *tl++ = txdr_unsigned(1); /* Only returns one layout. */
4595 txdr_hyper(offset, tl); tl += 2;
4596 txdr_hyper(len, tl); tl += 2;
4597 *tl++ = txdr_unsigned(iomode);
4598 *tl = txdr_unsigned(layouttype);
4599 nfsm_strtom(nd, layp, layoutlen);
4600 } else if (nd->nd_repstat == NFSERR_LAYOUTTRYLATER) {
4601 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4607 NFSEXITCODE2(error, nd);
4612 * nfsv4 layoutcommit service
4615 nfsrvd_layoutcommit(struct nfsrv_descript *nd, __unused int isdgram,
4616 vnode_t vp, struct nfsexstuff *exp)
4619 nfsv4stateid_t stateid;
4620 int error = 0, hasnewoff, hasnewmtime, layouttype, maxcnt, reclaim;
4622 uint64_t offset, len, newoff = 0, newsize;
4623 struct timespec newmtime;
4625 struct thread *p = curthread;
4628 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4629 nd->nd_repstat = NFSERR_WRONGSEC;
4632 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + 2 * NFSX_HYPER +
4634 offset = fxdr_hyper(tl); tl += 2;
4635 len = fxdr_hyper(tl); tl += 2;
4636 reclaim = fxdr_unsigned(int, *tl++);
4637 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4638 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4639 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4641 * For the special stateid of other all 0s and seqid == 1, set the
4642 * stateid to the current stateid, if it is set.
4644 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4645 stateid.other[1] == 0 && stateid.other[2] == 0) {
4646 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4647 stateid = nd->nd_curstateid;
4650 nd->nd_repstat = NFSERR_BADSTATEID;
4655 hasnewoff = fxdr_unsigned(int, *tl);
4656 if (hasnewoff != 0) {
4657 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
4658 newoff = fxdr_hyper(tl); tl += 2;
4660 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4661 hasnewmtime = fxdr_unsigned(int, *tl);
4662 if (hasnewmtime != 0) {
4663 NFSM_DISSECT(tl, uint32_t *, NFSX_V4TIME + 2 * NFSX_UNSIGNED);
4664 fxdr_nfsv4time(tl, &newmtime);
4665 tl += (NFSX_V4TIME / NFSX_UNSIGNED);
4667 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4668 layouttype = fxdr_unsigned(int, *tl++);
4669 maxcnt = fxdr_unsigned(int, *tl);
4671 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
4672 error = nfsrv_mtostr(nd, layp, maxcnt);
4676 nd->nd_repstat = nfsrv_layoutcommit(nd, vp, layouttype, hasnewoff,
4677 newoff, offset, len, hasnewmtime, &newmtime, reclaim, &stateid,
4678 maxcnt, layp, &hasnewsize, &newsize, nd->nd_cred, p);
4679 NFSD_DEBUG(4, "nfsrv_layoutcommit stat=%u\n", nd->nd_repstat);
4680 if (nd->nd_repstat == 0) {
4681 if (hasnewsize != 0) {
4682 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER);
4683 *tl++ = newnfs_true;
4684 txdr_hyper(newsize, tl);
4686 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4693 NFSEXITCODE2(error, nd);
4698 * nfsv4 layoutreturn service
4701 nfsrvd_layoutreturn(struct nfsrv_descript *nd, __unused int isdgram,
4702 vnode_t vp, struct nfsexstuff *exp)
4704 uint32_t *tl, *layp;
4705 nfsv4stateid_t stateid;
4706 int error = 0, fnd, kind, layouttype, iomode, maxcnt, reclaim;
4707 uint64_t offset, len;
4708 struct thread *p = curthread;
4711 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4712 nd->nd_repstat = NFSERR_WRONGSEC;
4715 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4717 layouttype = fxdr_unsigned(int, *tl++);
4718 iomode = fxdr_unsigned(int, *tl++);
4719 kind = fxdr_unsigned(int, *tl);
4720 NFSD_DEBUG(4, "layoutreturn recl=%d ltyp=%d iom=%d kind=%d\n", reclaim,
4721 layouttype, iomode, kind);
4722 if (kind == NFSV4LAYOUTRET_FILE) {
4723 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
4725 offset = fxdr_hyper(tl); tl += 2;
4726 len = fxdr_hyper(tl); tl += 2;
4727 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4728 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4729 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4732 * For the special stateid of other all 0s and seqid == 1, set
4733 * the stateid to the current stateid, if it is set.
4735 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4736 stateid.other[1] == 0 && stateid.other[2] == 0) {
4737 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4738 stateid = nd->nd_curstateid;
4741 nd->nd_repstat = NFSERR_BADSTATEID;
4746 maxcnt = fxdr_unsigned(int, *tl);
4748 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
4749 error = nfsrv_mtostr(nd, (char *)layp, maxcnt);
4754 if (reclaim == newnfs_true) {
4755 nd->nd_repstat = NFSERR_INVAL;
4761 nd->nd_repstat = nfsrv_layoutreturn(nd, vp, layouttype, iomode,
4762 offset, len, reclaim, kind, &stateid, maxcnt, layp, &fnd,
4764 NFSD_DEBUG(4, "nfsrv_layoutreturn stat=%u fnd=%d\n", nd->nd_repstat,
4766 if (nd->nd_repstat == 0) {
4767 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4770 NFSM_BUILD(tl, uint32_t *, NFSX_STATEID);
4771 *tl++ = txdr_unsigned(stateid.seqid);
4772 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
4779 NFSEXITCODE2(error, nd);
4784 * nfsv4 layout error service
4787 nfsrvd_layouterror(struct nfsrv_descript *nd, __unused int isdgram,
4788 vnode_t vp, struct nfsexstuff *exp)
4791 nfsv4stateid_t stateid;
4792 int cnt, error = 0, i, stat;
4794 char devid[NFSX_V4DEVICEID];
4795 uint64_t offset, len;
4797 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4798 nd->nd_repstat = NFSERR_WRONGSEC;
4801 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
4803 offset = fxdr_hyper(tl); tl += 2;
4804 len = fxdr_hyper(tl); tl += 2;
4805 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4806 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4807 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4808 cnt = fxdr_unsigned(int, *tl);
4809 NFSD_DEBUG(4, "layouterror off=%ju len=%ju cnt=%d\n", (uintmax_t)offset,
4810 (uintmax_t)len, cnt);
4812 * For the special stateid of other all 0s and seqid == 1, set
4813 * the stateid to the current stateid, if it is set.
4815 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4816 stateid.other[1] == 0 && stateid.other[2] == 0) {
4817 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4818 stateid = nd->nd_curstateid;
4821 nd->nd_repstat = NFSERR_BADSTATEID;
4827 * Ignore offset, len and stateid for now.
4829 for (i = 0; i < cnt; i++) {
4830 NFSM_DISSECT(tl, uint32_t *, NFSX_V4DEVICEID + 2 *
4832 NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
4833 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
4834 stat = fxdr_unsigned(int, *tl++);
4835 opnum = fxdr_unsigned(int, *tl);
4836 NFSD_DEBUG(4, "nfsrvd_layouterr op=%d stat=%d\n", opnum, stat);
4838 * Except for NFSERR_ACCES and NFSERR_STALE errors,
4839 * disable the mirror.
4841 if (stat != NFSERR_ACCES && stat != NFSERR_STALE)
4842 nfsrv_delds(devid, curthread);
4846 NFSEXITCODE2(error, nd);
4851 * nfsv4 layout stats service
4854 nfsrvd_layoutstats(struct nfsrv_descript *nd, __unused int isdgram,
4855 vnode_t vp, struct nfsexstuff *exp)
4858 nfsv4stateid_t stateid;
4860 int layouttype __unused;
4861 char devid[NFSX_V4DEVICEID] __unused;
4862 uint64_t offset, len, readcount, readbytes, writecount, writebytes
4865 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4866 nd->nd_repstat = NFSERR_WRONGSEC;
4869 NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_HYPER + NFSX_STATEID +
4870 NFSX_V4DEVICEID + 2 * NFSX_UNSIGNED);
4871 offset = fxdr_hyper(tl); tl += 2;
4872 len = fxdr_hyper(tl); tl += 2;
4873 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4874 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4875 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4876 readcount = fxdr_hyper(tl); tl += 2;
4877 readbytes = fxdr_hyper(tl); tl += 2;
4878 writecount = fxdr_hyper(tl); tl += 2;
4879 writebytes = fxdr_hyper(tl); tl += 2;
4880 NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
4881 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
4882 layouttype = fxdr_unsigned(int, *tl++);
4883 cnt = fxdr_unsigned(int, *tl);
4884 error = nfsm_advance(nd, NFSM_RNDUP(cnt), -1);
4887 NFSD_DEBUG(4, "layoutstats cnt=%d\n", cnt);
4889 * For the special stateid of other all 0s and seqid == 1, set
4890 * the stateid to the current stateid, if it is set.
4892 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4893 stateid.other[1] == 0 && stateid.other[2] == 0) {
4894 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4895 stateid = nd->nd_curstateid;
4898 nd->nd_repstat = NFSERR_BADSTATEID;
4904 * No use for the stats for now.
4908 NFSEXITCODE2(error, nd);
4913 * nfsv4 io_advise service
4916 nfsrvd_ioadvise(struct nfsrv_descript *nd, __unused int isdgram,
4917 vnode_t vp, struct nfsexstuff *exp)
4920 nfsv4stateid_t stateid;
4925 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4926 nd->nd_repstat = NFSERR_WRONGSEC;
4929 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
4930 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4931 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4932 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4933 offset = fxdr_hyper(tl); tl += 2;
4934 len = fxdr_hyper(tl);
4935 error = nfsrv_getattrbits(nd, &hints, NULL, NULL);
4939 * For the special stateid of other all 0s and seqid == 1, set
4940 * the stateid to the current stateid, if it is set.
4942 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4943 stateid.other[1] == 0 && stateid.other[2] == 0) {
4944 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4945 stateid = nd->nd_curstateid;
4948 nd->nd_repstat = NFSERR_BADSTATEID;
4954 nd->nd_repstat = NFSERR_INVAL;
4959 if (vp->v_type != VREG) {
4960 if (vp->v_type == VDIR)
4961 nd->nd_repstat = NFSERR_ISDIR;
4963 nd->nd_repstat = NFSERR_WRONGTYPE;
4968 * For now, we can only handle WILLNEED and DONTNEED and don't use
4971 if ((NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED) &&
4972 !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED)) ||
4973 (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED) &&
4974 !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED))) {
4976 if (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED)) {
4977 ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_WILLNEED);
4978 NFSZERO_ATTRBIT(&hints);
4980 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED);
4982 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
4984 ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_DONTNEED);
4985 NFSZERO_ATTRBIT(&hints);
4987 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED);
4989 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
4993 NFSZERO_ATTRBIT(&hints);
4994 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
4997 nfsrv_putattrbit(nd, &hints);
4998 NFSEXITCODE2(error, nd);
5002 NFSEXITCODE2(error, nd);
5007 * nfsv4 getdeviceinfo service
5010 nfsrvd_getdevinfo(struct nfsrv_descript *nd, __unused int isdgram,
5011 __unused vnode_t vp, __unused struct nfsexstuff *exp)
5013 uint32_t *tl, maxcnt, notify[NFSV4_NOTIFYBITMAP];
5014 int cnt, devaddrlen, error = 0, i, layouttype;
5015 char devid[NFSX_V4DEVICEID], *devaddr;
5018 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5019 nd->nd_repstat = NFSERR_WRONGSEC;
5022 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_V4DEVICEID);
5023 NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
5024 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5025 layouttype = fxdr_unsigned(int, *tl++);
5026 maxcnt = fxdr_unsigned(uint32_t, *tl++);
5027 cnt = fxdr_unsigned(int, *tl);
5028 NFSD_DEBUG(4, "getdevinfo ltyp=%d maxcnt=%u bitcnt=%d\n", layouttype,
5030 if (cnt > NFSV4_NOTIFYBITMAP || cnt < 0) {
5031 nd->nd_repstat = NFSERR_INVAL;
5035 NFSM_DISSECT(tl, uint32_t *, cnt * NFSX_UNSIGNED);
5036 for (i = 0; i < cnt; i++)
5037 notify[i] = fxdr_unsigned(uint32_t, *tl++);
5039 for (i = cnt; i < NFSV4_NOTIFYBITMAP; i++)
5043 * Check that the device id is not stale. Device ids are recreated
5044 * each time the nfsd threads are restarted.
5046 NFSBCOPY(devid, &dev_time, sizeof(dev_time));
5047 if (dev_time != nfsdev_time) {
5048 nd->nd_repstat = NFSERR_NOENT;
5052 /* Look for the device id. */
5053 nd->nd_repstat = nfsrv_getdevinfo(devid, layouttype, &maxcnt,
5054 notify, &devaddrlen, &devaddr);
5055 NFSD_DEBUG(4, "nfsrv_getdevinfo stat=%u\n", nd->nd_repstat);
5056 if (nd->nd_repstat == 0) {
5057 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5058 *tl = txdr_unsigned(layouttype);
5059 nfsm_strtom(nd, devaddr, devaddrlen);
5061 for (i = 0; i < NFSV4_NOTIFYBITMAP; i++) {
5065 NFSM_BUILD(tl, uint32_t *, (cnt + 1) * NFSX_UNSIGNED);
5066 *tl++ = txdr_unsigned(cnt);
5067 for (i = 0; i < cnt; i++)
5068 *tl++ = txdr_unsigned(notify[i]);
5069 } else if (nd->nd_repstat == NFSERR_TOOSMALL) {
5070 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5071 *tl = txdr_unsigned(maxcnt);
5074 NFSEXITCODE2(error, nd);
5079 * nfsv4 test stateid service
5082 nfsrvd_teststateid(struct nfsrv_descript *nd, __unused int isdgram,
5083 __unused vnode_t vp, __unused struct nfsexstuff *exp)
5086 nfsv4stateid_t *stateidp = NULL, *tstateidp;
5087 int cnt, error = 0, i, ret;
5088 struct thread *p = curthread;
5090 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5091 nd->nd_repstat = NFSERR_WRONGSEC;
5094 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5095 cnt = fxdr_unsigned(int, *tl);
5096 if (cnt <= 0 || cnt > 1024) {
5097 nd->nd_repstat = NFSERR_BADXDR;
5100 stateidp = mallocarray(cnt, sizeof(nfsv4stateid_t), M_TEMP, M_WAITOK);
5101 tstateidp = stateidp;
5102 for (i = 0; i < cnt; i++) {
5103 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
5104 tstateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
5105 NFSBCOPY(tl, tstateidp->other, NFSX_STATEIDOTHER);
5108 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5109 *tl = txdr_unsigned(cnt);
5110 tstateidp = stateidp;
5111 for (i = 0; i < cnt; i++) {
5112 ret = nfsrv_teststateid(nd, tstateidp, p);
5113 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5114 *tl = txdr_unsigned(ret);
5118 free(stateidp, M_TEMP);
5119 NFSEXITCODE2(error, nd);
5124 * nfs allocate service
5127 nfsrvd_allocate(struct nfsrv_descript *nd, __unused int isdgram,
5128 vnode_t vp, struct nfsexstuff *exp)
5131 struct nfsvattr forat;
5132 int error = 0, forat_ret = 1, gotproxystateid;
5134 struct nfsstate st, *stp = &st;
5135 struct nfslock lo, *lop = &lo;
5136 nfsv4stateid_t stateid;
5138 nfsattrbit_t attrbits;
5140 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5141 nd->nd_repstat = NFSERR_WRONGSEC;
5144 gotproxystateid = 0;
5145 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
5146 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5147 lop->lo_flags = NFSLCK_WRITE;
5148 stp->ls_ownerlen = 0;
5150 stp->ls_uid = nd->nd_cred->cr_uid;
5151 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
5152 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
5153 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
5154 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
5155 if ((nd->nd_flag & ND_NFSV41) != 0)
5156 clientid.qval = nd->nd_clientid.qval;
5157 else if (nd->nd_clientid.qval != clientid.qval)
5158 printf("EEK2 multiple clids\n");
5160 if ((nd->nd_flag & ND_NFSV41) != 0)
5161 printf("EEK! no clientid from session\n");
5162 nd->nd_flag |= ND_IMPLIEDCLID;
5163 nd->nd_clientid.qval = clientid.qval;
5165 stp->ls_stateid.other[2] = *tl++;
5167 * Don't allow this to be done for a DS.
5169 if ((nd->nd_flag & ND_DSSERVER) != 0)
5170 nd->nd_repstat = NFSERR_NOTSUPP;
5171 /* However, allow the proxy stateid. */
5172 if (stp->ls_stateid.seqid == 0xffffffff &&
5173 stp->ls_stateid.other[0] == 0x55555555 &&
5174 stp->ls_stateid.other[1] == 0x55555555 &&
5175 stp->ls_stateid.other[2] == 0x55555555)
5176 gotproxystateid = 1;
5177 off = fxdr_hyper(tl); tl += 2;
5178 lop->lo_first = off;
5179 len = fxdr_hyper(tl);
5180 lop->lo_end = off + len;
5182 * Paranoia, just in case it wraps around, which shouldn't
5183 * ever happen anyhow.
5185 if (nd->nd_repstat == 0 && (lop->lo_end < lop->lo_first || len <= 0))
5186 nd->nd_repstat = NFSERR_INVAL;
5188 if (nd->nd_repstat == 0 && vnode_vtype(vp) != VREG)
5189 nd->nd_repstat = NFSERR_WRONGTYPE;
5190 NFSZERO_ATTRBIT(&attrbits);
5191 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5192 forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits);
5193 if (nd->nd_repstat == 0)
5194 nd->nd_repstat = forat_ret;
5195 if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid ||
5196 NFSVNO_EXSTRICTACCESS(exp)))
5197 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp,
5198 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5200 if (nd->nd_repstat == 0 && gotproxystateid == 0)
5201 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
5202 &stateid, exp, nd, curthread);
5204 if (nd->nd_repstat == 0)
5205 nd->nd_repstat = nfsvno_allocate(vp, off, len, nd->nd_cred,
5208 NFSEXITCODE2(0, nd);
5212 NFSEXITCODE2(error, nd);
5220 nfsrvd_copy_file_range(struct nfsrv_descript *nd, __unused int isdgram,
5221 vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
5225 int cnt, error = 0, ret;
5226 off_t inoff, outoff;
5229 struct nfsstate inst, outst, *instp = &inst, *outstp = &outst;
5230 struct nfslock inlo, outlo, *inlop = &inlo, *outlop = &outlo;
5232 nfsv4stateid_t stateid;
5233 nfsattrbit_t attrbits;
5234 void *rl_rcookie, *rl_wcookie;
5236 rl_rcookie = rl_wcookie = NULL;
5237 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5238 nd->nd_repstat = NFSERR_WRONGSEC;
5241 if (nfsrv_devidcnt > 0) {
5243 * For a pNFS server, reply NFSERR_NOTSUPP so that the client
5244 * will do the copy via I/O on the DS(s).
5246 nd->nd_repstat = NFSERR_NOTSUPP;
5250 /* Copying a byte range within the same file is not allowed. */
5251 nd->nd_repstat = NFSERR_INVAL;
5254 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_STATEID + 3 * NFSX_HYPER +
5256 instp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
5257 inlop->lo_flags = NFSLCK_READ;
5258 instp->ls_ownerlen = 0;
5259 instp->ls_op = NULL;
5260 instp->ls_uid = nd->nd_cred->cr_uid;
5261 instp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5262 clientid.lval[0] = instp->ls_stateid.other[0] = *tl++;
5263 clientid.lval[1] = instp->ls_stateid.other[1] = *tl++;
5264 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0)
5265 clientid.qval = nd->nd_clientid.qval;
5266 instp->ls_stateid.other[2] = *tl++;
5267 outstp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5268 outlop->lo_flags = NFSLCK_WRITE;
5269 outstp->ls_ownerlen = 0;
5270 outstp->ls_op = NULL;
5271 outstp->ls_uid = nd->nd_cred->cr_uid;
5272 outstp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5273 outstp->ls_stateid.other[0] = *tl++;
5274 outstp->ls_stateid.other[1] = *tl++;
5275 outstp->ls_stateid.other[2] = *tl++;
5276 inoff = fxdr_hyper(tl); tl += 2;
5277 inlop->lo_first = inoff;
5278 outoff = fxdr_hyper(tl); tl += 2;
5279 outlop->lo_first = outoff;
5280 len = fxdr_hyper(tl); tl += 2;
5282 /* len == 0 means to EOF. */
5283 inlop->lo_end = OFF_MAX;
5284 outlop->lo_end = OFF_MAX;
5286 inlop->lo_end = inlop->lo_first + len;
5287 outlop->lo_end = outlop->lo_first + len;
5291 * At this time only consecutive, synchronous copy is supported,
5292 * so ca_consecutive and ca_synchronous can be ignored.
5296 cnt = fxdr_unsigned(int, *tl);
5297 if ((nd->nd_flag & ND_DSSERVER) != 0 || cnt != 0)
5298 nd->nd_repstat = NFSERR_NOTSUPP;
5299 if (nd->nd_repstat == 0 && (inoff > OFF_MAX || outoff > OFF_MAX ||
5300 inlop->lo_end > OFF_MAX || outlop->lo_end > OFF_MAX ||
5301 inlop->lo_end < inlop->lo_first || outlop->lo_end <
5303 nd->nd_repstat = NFSERR_INVAL;
5305 if (nd->nd_repstat == 0 && vnode_vtype(vp) != VREG)
5306 nd->nd_repstat = NFSERR_WRONGTYPE;
5308 /* Check permissions for the input file. */
5309 NFSZERO_ATTRBIT(&attrbits);
5310 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5311 ret = nfsvno_getattr(vp, &at, nd, curthread, 1, &attrbits);
5312 if (nd->nd_repstat == 0)
5313 nd->nd_repstat = ret;
5314 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5315 NFSVNO_EXSTRICTACCESS(exp)))
5316 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp,
5317 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5319 if (nd->nd_repstat == 0)
5320 nd->nd_repstat = nfsrv_lockctrl(vp, &instp, &inlop, NULL,
5321 clientid, &stateid, exp, nd, curthread);
5323 if (nd->nd_repstat != 0)
5326 error = NFSVOPLOCK(tovp, LK_SHARED);
5329 if (vnode_vtype(tovp) != VREG)
5330 nd->nd_repstat = NFSERR_WRONGTYPE;
5332 /* For the output file, we only need the Owner attribute. */
5333 ret = nfsvno_getattr(tovp, &at, nd, curthread, 1, &attrbits);
5334 if (nd->nd_repstat == 0)
5335 nd->nd_repstat = ret;
5336 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5337 NFSVNO_EXSTRICTACCESS(exp)))
5338 nd->nd_repstat = nfsvno_accchk(tovp, VWRITE, nd->nd_cred, toexp,
5339 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5341 if (nd->nd_repstat == 0)
5342 nd->nd_repstat = nfsrv_lockctrl(tovp, &outstp, &outlop, NULL,
5343 clientid, &stateid, toexp, nd, curthread);
5346 /* Range lock the byte ranges for both invp and outvp. */
5347 if (nd->nd_repstat == 0) {
5350 rl_wcookie = vn_rangelock_wlock(tovp, outoff,
5352 rl_rcookie = vn_rangelock_tryrlock(vp, inoff,
5355 rl_wcookie = vn_rangelock_wlock(tovp, outoff,
5357 rl_rcookie = vn_rangelock_tryrlock(vp, inoff,
5360 if (rl_rcookie != NULL)
5362 vn_rangelock_unlock(tovp, rl_wcookie);
5364 rl_rcookie = vn_rangelock_rlock(vp, inoff,
5367 rl_rcookie = vn_rangelock_rlock(vp, inoff,
5369 vn_rangelock_unlock(vp, rl_rcookie);
5372 error = NFSVOPLOCK(vp, LK_SHARED);
5374 ret = nfsvno_getattr(vp, &at, nd, curthread, 1, NULL);
5377 * Since invp is range locked, na_size should
5380 if (len == 0 && at.na_size > inoff) {
5382 * If len == 0, set it based on invp's
5383 * size. If offset is past EOF, just
5386 len = at.na_size - inoff;
5387 } else if (nfsrv_linux42server == 0 &&
5388 inoff + len > at.na_size) {
5390 * RFC-7862 says that NFSERR_INVAL must
5391 * be returned when inoff + len exceeds
5392 * the file size, however the NFSv4.2
5393 * Linux client likes to do this, so
5394 * only check if nfsrv_linux42server
5397 nd->nd_repstat = NFSERR_INVAL;
5401 if (ret != 0 && nd->nd_repstat == 0)
5402 nd->nd_repstat = ret;
5403 } else if (nd->nd_repstat == 0)
5404 nd->nd_repstat = error;
5408 * Do the actual copy to an upper limit of vfs.nfs.maxcopyrange.
5409 * This limit is applied to ensure that the RPC replies in a
5412 if (len > nfs_maxcopyrange)
5413 xfer = nfs_maxcopyrange;
5416 if (nd->nd_repstat == 0) {
5417 nd->nd_repstat = vn_copy_file_range(vp, &inoff, tovp, &outoff,
5418 &xfer, 0, nd->nd_cred, nd->nd_cred, NULL);
5419 if (nd->nd_repstat == 0)
5423 /* Unlock the ranges. */
5424 if (rl_rcookie != NULL)
5425 vn_rangelock_unlock(vp, rl_rcookie);
5426 if (rl_wcookie != NULL)
5427 vn_rangelock_unlock(tovp, rl_wcookie);
5429 if (nd->nd_repstat == 0) {
5430 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_HYPER +
5432 *tl++ = txdr_unsigned(0); /* No callback ids. */
5433 txdr_hyper(len, tl); tl += 2;
5434 *tl++ = txdr_unsigned(NFSWRITE_UNSTABLE);
5435 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
5436 *tl++ = txdr_unsigned(nfsboottime.tv_usec);
5437 *tl++ = newnfs_true;
5443 NFSEXITCODE2(error, nd);
5448 NFSEXITCODE2(error, nd);
5456 nfsrvd_seek(struct nfsrv_descript *nd, __unused int isdgram,
5457 vnode_t vp, struct nfsexstuff *exp)
5461 int content, error = 0;
5464 nfsattrbit_t attrbits;
5467 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5468 nd->nd_repstat = NFSERR_WRONGSEC;
5471 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + NFSX_HYPER + NFSX_UNSIGNED);
5472 /* Ignore the stateid for now. */
5473 tl += (NFSX_STATEID / NFSX_UNSIGNED);
5474 off = fxdr_hyper(tl); tl += 2;
5475 content = fxdr_unsigned(int, *tl);
5476 if (content == NFSV4CONTENT_DATA)
5478 else if (content == NFSV4CONTENT_HOLE)
5481 nd->nd_repstat = NFSERR_BADXDR;
5482 if (nd->nd_repstat == 0 && vnode_vtype(vp) == VDIR)
5483 nd->nd_repstat = NFSERR_ISDIR;
5484 if (nd->nd_repstat == 0 && vnode_vtype(vp) != VREG)
5485 nd->nd_repstat = NFSERR_WRONGTYPE;
5486 if (nd->nd_repstat == 0 && off < 0)
5487 nd->nd_repstat = NFSERR_NXIO;
5488 if (nd->nd_repstat == 0) {
5489 /* Check permissions for the input file. */
5490 NFSZERO_ATTRBIT(&attrbits);
5491 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5492 nd->nd_repstat = nfsvno_getattr(vp, &at, nd, curthread, 1,
5495 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5496 NFSVNO_EXSTRICTACCESS(exp)))
5497 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp,
5498 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5500 if (nd->nd_repstat != 0)
5503 /* nfsvno_seek() unlocks and vrele()s the vp. */
5504 nd->nd_repstat = nfsvno_seek(nd, vp, cmd, &off, content, &eof,
5505 nd->nd_cred, curthread);
5506 if (nd->nd_repstat == 0 && eof && content == NFSV4CONTENT_DATA &&
5507 nfsrv_linux42server != 0)
5508 nd->nd_repstat = NFSERR_NXIO;
5509 if (nd->nd_repstat == 0) {
5510 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER);
5512 *tl++ = newnfs_true;
5514 *tl++ = newnfs_false;
5515 txdr_hyper(off, tl);
5517 NFSEXITCODE2(error, nd);
5521 NFSEXITCODE2(error, nd);
5526 * nfs get extended attribute service
5529 nfsrvd_getxattr(struct nfsrv_descript *nd, __unused int isdgram,
5530 vnode_t vp, __unused struct nfsexstuff *exp)
5533 struct mbuf *mp = NULL, *mpend = NULL;
5536 struct thread *p = curthread;
5539 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5540 nd->nd_repstat = NFSERR_WRONGSEC;
5543 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5544 len = fxdr_unsigned(int, *tl);
5546 nd->nd_repstat = NFSERR_BADXDR;
5549 if (len > EXTATTR_MAXNAMELEN) {
5550 nd->nd_repstat = NFSERR_NOXATTR;
5553 name = malloc(len + 1, M_TEMP, M_WAITOK);
5554 nd->nd_repstat = nfsrv_mtostr(nd, name, len);
5555 if (nd->nd_repstat == 0)
5556 nd->nd_repstat = nfsvno_getxattr(vp, name, nd->nd_maxresp,
5557 nd->nd_cred, p, &mp, &mpend, &len);
5558 if (nd->nd_repstat == ENOATTR)
5559 nd->nd_repstat = NFSERR_NOXATTR;
5560 else if (nd->nd_repstat == EOPNOTSUPP)
5561 nd->nd_repstat = NFSERR_NOTSUPP;
5562 if (nd->nd_repstat == 0) {
5563 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5564 *tl = txdr_unsigned(len);
5566 nd->nd_mb->m_next = mp;
5568 nd->nd_bpos = mtod(mpend, caddr_t) + mpend->m_len;
5574 if (nd->nd_repstat == 0)
5575 nd->nd_repstat = error;
5577 NFSEXITCODE2(0, nd);
5582 * nfs set extended attribute service
5585 nfsrvd_setxattr(struct nfsrv_descript *nd, __unused int isdgram,
5586 vnode_t vp, __unused struct nfsexstuff *exp)
5589 struct nfsvattr ova, nva;
5590 nfsattrbit_t attrbits;
5591 int error, len, opt;
5594 struct thread *p = curthread;
5598 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5599 nd->nd_repstat = NFSERR_WRONGSEC;
5602 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
5603 opt = fxdr_unsigned(int, *tl++);
5604 len = fxdr_unsigned(int, *tl);
5606 nd->nd_repstat = NFSERR_BADXDR;
5609 if (len > EXTATTR_MAXNAMELEN) {
5610 nd->nd_repstat = NFSERR_NOXATTR;
5613 name = malloc(len + 1, M_TEMP, M_WAITOK);
5614 error = nfsrv_mtostr(nd, name, len);
5617 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5618 len = fxdr_unsigned(int, *tl);
5619 if (len < 0 || len > IOSIZE_MAX) {
5620 nd->nd_repstat = NFSERR_XATTR2BIG;
5624 case NFSV4SXATTR_CREATE:
5625 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL,
5626 &siz, nd->nd_cred, p);
5627 if (error != ENOATTR)
5628 nd->nd_repstat = NFSERR_EXIST;
5631 case NFSV4SXATTR_REPLACE:
5632 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL,
5633 &siz, nd->nd_cred, p);
5635 nd->nd_repstat = NFSERR_NOXATTR;
5637 case NFSV4SXATTR_EITHER:
5640 nd->nd_repstat = NFSERR_BADXDR;
5642 if (nd->nd_repstat != 0)
5645 /* Now, do the Set Extended attribute, with Change before and after. */
5646 NFSZERO_ATTRBIT(&attrbits);
5647 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
5648 nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits);
5649 if (nd->nd_repstat == 0) {
5650 nd->nd_repstat = nfsvno_setxattr(vp, name, len, nd->nd_md,
5651 nd->nd_dpos, nd->nd_cred, p);
5652 if (nd->nd_repstat == ENXIO)
5653 nd->nd_repstat = NFSERR_XATTR2BIG;
5655 if (nd->nd_repstat == 0 && len > 0)
5656 nd->nd_repstat = nfsm_advance(nd, NFSM_RNDUP(len), -1);
5657 if (nd->nd_repstat == 0)
5658 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
5659 if (nd->nd_repstat == 0) {
5660 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED);
5661 *tl++ = newnfs_true;
5662 txdr_hyper(ova.na_filerev, tl); tl += 2;
5663 txdr_hyper(nva.na_filerev, tl);
5668 if (nd->nd_repstat == 0)
5669 nd->nd_repstat = error;
5671 NFSEXITCODE2(0, nd);
5676 * nfs remove extended attribute service
5679 nfsrvd_rmxattr(struct nfsrv_descript *nd, __unused int isdgram,
5680 vnode_t vp, __unused struct nfsexstuff *exp)
5683 struct nfsvattr ova, nva;
5684 nfsattrbit_t attrbits;
5687 struct thread *p = curthread;
5691 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5692 nd->nd_repstat = NFSERR_WRONGSEC;
5695 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5696 len = fxdr_unsigned(int, *tl);
5698 nd->nd_repstat = NFSERR_BADXDR;
5701 if (len > EXTATTR_MAXNAMELEN) {
5702 nd->nd_repstat = NFSERR_NOXATTR;
5705 name = malloc(len + 1, M_TEMP, M_WAITOK);
5706 error = nfsrv_mtostr(nd, name, len);
5710 if ((nd->nd_flag & ND_IMPLIEDCLID) == 0) {
5711 printf("EEK! nfsrvd_rmxattr: no implied clientid\n");
5712 error = NFSERR_NOXATTR;
5716 * Now, do the Remove Extended attribute, with Change before and
5719 NFSZERO_ATTRBIT(&attrbits);
5720 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
5721 nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits);
5722 if (nd->nd_repstat == 0) {
5723 nd->nd_repstat = nfsvno_rmxattr(nd, vp, name, nd->nd_cred, p);
5724 if (nd->nd_repstat == ENOATTR)
5725 nd->nd_repstat = NFSERR_NOXATTR;
5727 if (nd->nd_repstat == 0)
5728 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
5729 if (nd->nd_repstat == 0) {
5730 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED);
5731 *tl++ = newnfs_true;
5732 txdr_hyper(ova.na_filerev, tl); tl += 2;
5733 txdr_hyper(nva.na_filerev, tl);
5738 if (nd->nd_repstat == 0)
5739 nd->nd_repstat = error;
5741 NFSEXITCODE2(0, nd);
5746 * nfs list extended attribute service
5749 nfsrvd_listxattr(struct nfsrv_descript *nd, __unused int isdgram,
5750 vnode_t vp, __unused struct nfsexstuff *exp)
5752 uint32_t cnt, *tl, len, len2, i, pos, retlen;
5754 uint64_t cookie, cookie2;
5757 struct thread *p = curthread;
5761 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5762 nd->nd_repstat = NFSERR_WRONGSEC;
5765 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
5767 * The cookie doesn't need to be in net byte order, but FreeBSD
5768 * does so to make it more readable in packet traces.
5770 cookie = fxdr_hyper(tl); tl += 2;
5771 len = fxdr_unsigned(uint32_t, *tl);
5772 if (len == 0 || cookie >= IOSIZE_MAX) {
5773 nd->nd_repstat = NFSERR_BADXDR;
5776 if (len > nd->nd_maxresp - NFS_MAXXDR)
5777 len = nd->nd_maxresp - NFS_MAXXDR;
5779 nd->nd_repstat = nfsvno_listxattr(vp, cookie, nd->nd_cred, p, &buf,
5781 if (nd->nd_repstat == EOPNOTSUPP)
5782 nd->nd_repstat = NFSERR_NOTSUPP;
5783 if (nd->nd_repstat == 0) {
5784 cookie2 = cookie + len;
5785 if (cookie2 < cookie)
5786 nd->nd_repstat = NFSERR_BADXDR;
5788 if (nd->nd_repstat == 0) {
5789 /* Now copy the entries out. */
5790 retlen = NFSX_HYPER + 2 * NFSX_UNSIGNED;
5791 if (len == 0 && retlen <= len2) {
5792 /* The cookie was at eof. */
5793 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 *
5795 txdr_hyper(cookie2, tl); tl += 2;
5796 *tl++ = txdr_unsigned(0);
5801 /* Sanity check the cookie. */
5802 for (pos = 0; pos < len; pos += (i + 1)) {
5807 if (pos != cookie) {
5808 nd->nd_repstat = NFSERR_INVAL;
5812 /* Loop around copying the entrie(s) out. */
5816 while (i < len && len2 >= retlen + NFSM_RNDUP(i) +
5819 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER +
5821 txdr_hyper(cookie2, tl); tl += 2;
5823 retlen += nfsm_strtom(nd, &buf[pos + 1], i);
5830 * eof is set true/false by nfsvno_listxattr(), but if we
5831 * can't copy all entries returned by nfsvno_listxattr(),
5832 * we are not at eof.
5837 /* *tl is set above. */
5838 *tl = txdr_unsigned(cnt);
5839 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5845 nd->nd_repstat = NFSERR_TOOSMALL;
5850 if (nd->nd_repstat == 0)
5851 nd->nd_repstat = error;
5853 NFSEXITCODE2(0, nd);
5858 * nfsv4 service not supported
5861 nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram,
5862 __unused vnode_t vp, __unused struct nfsexstuff *exp)
5865 nd->nd_repstat = NFSERR_NOTSUPP;
5866 NFSEXITCODE2(0, nd);