2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Rick Macklem at The University of Guelph.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
40 #include "opt_inet6.h"
42 * nfs version 2, 3 and 4 server calls to vnode ops
43 * - these routines generally have 3 phases
44 * 1 - break down and validate rpc request in mbuf list
45 * 2 - do the vnode ops for the request, usually by calling a nfsvno_XXX()
46 * function in nfsd_port.c
47 * 3 - build the rpc reply in an mbuf list
48 * For nfsv4, these functions are called for each Op within the Compound RPC.
51 #include <fs/nfs/nfsport.h>
52 #include <sys/extattr.h>
53 #include <sys/filio.h>
56 extern u_int32_t newnfs_false, newnfs_true;
57 extern enum vtype nv34tov_type[8];
58 extern struct timeval nfsboottime;
59 extern int nfs_rootfhset;
60 extern int nfsrv_enable_crossmntpt;
61 extern int nfsrv_statehashsize;
62 extern int nfsrv_layouthashsize;
63 extern time_t nfsdev_time;
64 extern volatile int nfsrv_devidcnt;
65 extern int nfsd_debuglevel;
66 extern u_long sb_max_adj;
67 extern int nfsrv_pnfsatime;
68 extern int nfsrv_maxpnfsmirror;
69 extern int nfs_maxcopyrange;
71 static int nfs_async = 0;
72 SYSCTL_DECL(_vfs_nfsd);
73 SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0,
74 "Tell client that writes were synced even though they were not");
75 extern int nfsrv_doflexfile;
76 SYSCTL_INT(_vfs_nfsd, OID_AUTO, default_flexfile, CTLFLAG_RW,
77 &nfsrv_doflexfile, 0, "Make Flex File Layout the default for pNFS");
78 static int nfsrv_linux42server = 1;
79 SYSCTL_INT(_vfs_nfsd, OID_AUTO, linux42server, CTLFLAG_RW,
80 &nfsrv_linux42server, 0,
81 "Enable Linux style NFSv4.2 server (non-RFC compliant)");
82 static bool nfsrv_openaccess = true;
83 SYSCTL_BOOL(_vfs_nfsd, OID_AUTO, v4openaccess, CTLFLAG_RW,
85 "Enable Linux style NFSv4 Open access check");
88 * This list defines the GSS mechanisms supported.
89 * (Don't ask me how you get these strings from the RFC stuff like
90 * iso(1), org(3)... but someone did it, so I don't need to know.)
92 static struct nfsgss_mechlist nfsgss_mechlist[] = {
93 { 9, "\052\206\110\206\367\022\001\002\002", 11 },
98 static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
99 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
100 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
101 int *diraft_retp, nfsattrbit_t *attrbitp,
102 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
104 static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
105 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
106 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
107 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
108 NFSPROC_T *p, struct nfsexstuff *exp);
111 * nfs access service (not a part of NFS V2)
114 nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram,
115 vnode_t vp, struct nfsexstuff *exp)
118 int getret, error = 0;
120 u_int32_t testmode, nfsmode, supported = 0;
122 struct thread *p = curthread;
124 if (nd->nd_repstat) {
125 nfsrv_postopattr(nd, 1, &nva);
128 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
129 nfsmode = fxdr_unsigned(u_int32_t, *tl);
130 if ((nd->nd_flag & ND_NFSV4) &&
131 (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP |
132 NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE |
133 NFSACCESS_EXECUTE | NFSACCESS_XAREAD | NFSACCESS_XAWRITE |
134 NFSACCESS_XALIST))) {
135 nd->nd_repstat = NFSERR_INVAL;
139 if (nfsmode & NFSACCESS_READ) {
140 supported |= NFSACCESS_READ;
141 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
142 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
143 nfsmode &= ~NFSACCESS_READ;
145 if (nfsmode & NFSACCESS_MODIFY) {
146 supported |= NFSACCESS_MODIFY;
147 if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
148 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
149 nfsmode &= ~NFSACCESS_MODIFY;
151 if (nfsmode & NFSACCESS_EXTEND) {
152 supported |= NFSACCESS_EXTEND;
153 if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p,
154 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
155 nfsmode &= ~NFSACCESS_EXTEND;
157 if (nfsmode & NFSACCESS_XAREAD) {
158 supported |= NFSACCESS_XAREAD;
159 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
160 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
161 nfsmode &= ~NFSACCESS_XAREAD;
163 if (nfsmode & NFSACCESS_XAWRITE) {
164 supported |= NFSACCESS_XAWRITE;
165 if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
166 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
167 nfsmode &= ~NFSACCESS_XAWRITE;
169 if (nfsmode & NFSACCESS_XALIST) {
170 supported |= NFSACCESS_XALIST;
171 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
172 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
173 nfsmode &= ~NFSACCESS_XALIST;
175 if (nfsmode & NFSACCESS_DELETE) {
176 supported |= NFSACCESS_DELETE;
177 if (vp->v_type == VDIR)
178 deletebit = VDELETE_CHILD;
181 if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p,
182 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
183 nfsmode &= ~NFSACCESS_DELETE;
185 if (vnode_vtype(vp) == VDIR)
186 testmode = NFSACCESS_LOOKUP;
188 testmode = NFSACCESS_EXECUTE;
189 if (nfsmode & testmode) {
190 supported |= (nfsmode & testmode);
191 if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p,
192 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
193 nfsmode &= ~testmode;
195 nfsmode &= supported;
196 if (nd->nd_flag & ND_NFSV3) {
197 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
198 nfsrv_postopattr(nd, getret, &nva);
201 if (nd->nd_flag & ND_NFSV4) {
202 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
203 *tl++ = txdr_unsigned(supported);
205 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
206 *tl = txdr_unsigned(nfsmode);
213 NFSEXITCODE2(error, nd);
218 * nfs getattr service
221 nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
222 vnode_t vp, __unused struct nfsexstuff *exp)
226 int at_root = 0, error = 0, supports_nfsv4acls;
227 struct nfsreferral *refp;
228 nfsattrbit_t attrbits, tmpbits;
230 struct vnode *tvp = NULL;
232 uint64_t mounted_on_fileno = 0;
234 struct thread *p = curthread;
238 if (nd->nd_flag & ND_NFSV4) {
239 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
246 * Check for a referral.
248 refp = nfsv4root_getreferral(vp, NULL, 0);
250 (void) nfsrv_putreferralattr(nd, &attrbits, refp, 1,
255 if (nd->nd_repstat == 0) {
257 NFSSET_ATTRBIT(&tmpbits, &attrbits);
260 * GETATTR with write-only attr time_access_set and time_modify_set
261 * should return NFS4ERR_INVAL.
263 if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEACCESSSET) ||
264 NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEMODIFYSET)){
265 error = NFSERR_INVAL;
269 if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) {
270 NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL);
271 accmode |= VREAD_ACL;
273 if (NFSNONZERO_ATTRBIT(&tmpbits))
274 accmode |= VREAD_ATTRIBUTES;
276 nd->nd_repstat = nfsvno_accchk(vp, accmode,
277 nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
278 NFSACCCHK_VPISLOCKED, NULL);
282 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
283 if (!nd->nd_repstat) {
284 if (nd->nd_flag & ND_NFSV4) {
285 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE))
286 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
288 nd->nd_repstat = nfsrv_checkgetattr(nd, vp,
290 if (nd->nd_repstat == 0) {
291 supports_nfsv4acls = nfs_supportsnfsv4acls(vp);
293 if (nfsrv_enable_crossmntpt != 0 &&
294 vp->v_type == VDIR &&
295 (vp->v_vflag & VV_ROOT) != 0 &&
297 tvp = mp->mnt_vnodecovered;
305 if ((nd->nd_repstat =
306 NFSVOPLOCK(tvp, LK_SHARED)) == 0) {
307 nd->nd_repstat = VOP_GETATTR(
308 tvp, &va, nd->nd_cred);
312 if (nd->nd_repstat == 0)
313 mounted_on_fileno = (uint64_t)
318 if (nd->nd_repstat == 0)
319 nd->nd_repstat = vfs_busy(mp, 0);
321 if (nd->nd_repstat == 0) {
322 (void)nfsvno_fillattr(nd, mp, vp, &nva,
323 &fh, 0, &attrbits, nd->nd_cred, p,
324 isdgram, 1, supports_nfsv4acls,
325 at_root, mounted_on_fileno);
332 nfsrv_fillattr(nd, &nva);
340 NFSEXITCODE2(error, nd);
345 * nfs setattr service
348 nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
349 vnode_t vp, struct nfsexstuff *exp)
351 struct nfsvattr nva, nva2;
353 int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
355 struct timespec guard = { 0, 0 };
356 nfsattrbit_t attrbits, retbits;
357 nfsv4stateid_t stateid;
358 NFSACL_T *aclp = NULL;
359 struct thread *p = curthread;
361 if (nd->nd_repstat) {
362 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
365 #ifdef NFS4_ACL_EXTATTR_NAME
366 aclp = acl_alloc(M_WAITOK);
370 NFSVNO_ATTRINIT(&nva);
371 if (nd->nd_flag & ND_NFSV4) {
372 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
373 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
374 stateid.other[0] = *tl++;
375 stateid.other[1] = *tl++;
376 stateid.other[2] = *tl;
377 if (stateid.other[0] == 0x55555555 &&
378 stateid.other[1] == 0x55555555 &&
379 stateid.other[2] == 0x55555555 &&
380 stateid.seqid == 0xffffffff)
383 error = nfsrv_sattr(nd, vp, &nva, &attrbits, aclp, p);
387 /* For NFSv4, only va_uid is used from nva2. */
388 NFSZERO_ATTRBIT(&retbits);
389 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
390 preat_ret = nfsvno_getattr(vp, &nva2, nd, p, 1, &retbits);
392 nd->nd_repstat = preat_ret;
394 NFSZERO_ATTRBIT(&retbits);
395 if (nd->nd_flag & ND_NFSV3) {
396 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
397 gcheck = fxdr_unsigned(int, *tl);
399 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
400 fxdr_nfsv3time(tl, &guard);
402 if (!nd->nd_repstat && gcheck &&
403 (nva2.na_ctime.tv_sec != guard.tv_sec ||
404 nva2.na_ctime.tv_nsec != guard.tv_nsec))
405 nd->nd_repstat = NFSERR_NOT_SYNC;
406 if (nd->nd_repstat) {
408 #ifdef NFS4_ACL_EXTATTR_NAME
411 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
414 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
415 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
418 * Now that we have all the fields, lets do it.
419 * If the size is being changed write access is required, otherwise
420 * just check for a read only file system.
422 if (!nd->nd_repstat) {
423 if (NFSVNO_NOTSETSIZE(&nva)) {
424 if (NFSVNO_EXRDONLY(exp) ||
425 (vfs_flags(vp->v_mount) & MNT_RDONLY))
426 nd->nd_repstat = EROFS;
428 if (vnode_vtype(vp) != VREG)
429 nd->nd_repstat = EINVAL;
430 else if (nva2.na_uid != nd->nd_cred->cr_uid ||
431 NFSVNO_EXSTRICTACCESS(exp))
432 nd->nd_repstat = nfsvno_accchk(vp,
433 VWRITE, nd->nd_cred, exp, p,
434 NFSACCCHK_NOOVERRIDE,
435 NFSACCCHK_VPISLOCKED, NULL);
439 * Proxy operations from the MDS are allowed via the all 0s special
442 if (nd->nd_repstat == 0 && (nd->nd_flag & ND_NFSV4) != 0 &&
443 gotproxystateid == 0)
444 nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid,
445 &nva, &attrbits, exp, p);
447 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
449 * For V4, try setting the attrbutes in sets, so that the
450 * reply bitmap will be correct for an error case.
452 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) ||
453 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) {
454 NFSVNO_ATTRINIT(&nva2);
455 NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid);
456 NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid);
457 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
459 if (!nd->nd_repstat) {
460 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER))
461 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
462 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP))
463 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP);
466 if (!nd->nd_repstat &&
467 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) {
468 NFSVNO_ATTRINIT(&nva2);
469 NFSVNO_SETATTRVAL(&nva2, size, nva.na_size);
470 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
473 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE);
475 if (!nd->nd_repstat &&
476 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) ||
477 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) {
478 NFSVNO_ATTRINIT(&nva2);
479 NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime);
480 NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime);
481 if (nva.na_vaflags & VA_UTIMES_NULL) {
482 nva2.na_vaflags |= VA_UTIMES_NULL;
483 NFSVNO_SETACTIVE(&nva2, vaflags);
485 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
487 if (!nd->nd_repstat) {
488 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET))
489 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET);
490 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))
491 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET);
494 if (!nd->nd_repstat &&
495 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE) ||
496 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED))) {
497 NFSVNO_ATTRINIT(&nva2);
498 NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode);
499 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
501 if (!nd->nd_repstat) {
502 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE))
503 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
504 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED))
505 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODESETMASKED);
509 #ifdef NFS4_ACL_EXTATTR_NAME
510 if (!nd->nd_repstat && aclp->acl_cnt > 0 &&
511 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) {
512 nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
514 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL);
517 } else if (!nd->nd_repstat) {
518 nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p,
521 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) {
522 postat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
524 nd->nd_repstat = postat_ret;
527 #ifdef NFS4_ACL_EXTATTR_NAME
530 if (nd->nd_flag & ND_NFSV3)
531 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
532 else if (nd->nd_flag & ND_NFSV4)
533 (void) nfsrv_putattrbit(nd, &retbits);
534 else if (!nd->nd_repstat)
535 nfsrv_fillattr(nd, &nva);
542 #ifdef NFS4_ACL_EXTATTR_NAME
545 if (nd->nd_flag & ND_NFSV4) {
547 * For all nd_repstat, the V4 reply includes a bitmap,
548 * even NFSERR_BADXDR, which is what this will end up
551 (void) nfsrv_putattrbit(nd, &retbits);
553 NFSEXITCODE2(error, nd);
559 * (Also performs lookup parent for v4)
562 nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
563 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
565 struct nameidata named;
566 vnode_t vp, dirp = NULL;
567 int error = 0, dattr_ret = 1;
568 struct nfsvattr nva, dattr;
571 struct thread *p = curthread;
573 if (nd->nd_repstat) {
574 nfsrv_postopattr(nd, dattr_ret, &dattr);
579 * For some reason, if dp is a symlink, the error
580 * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR.
582 if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) {
583 nd->nd_repstat = NFSERR_SYMLINK;
588 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
589 LOCKLEAF | SAVESTART);
590 nfsvno_setpathbuf(&named, &bufp, &hashp);
591 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
594 nfsvno_relpathbuf(&named);
597 if (!nd->nd_repstat) {
598 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
601 nfsvno_relpathbuf(&named);
603 if (nd->nd_repstat) {
605 if (nd->nd_flag & ND_NFSV3)
606 dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p,
610 if (nd->nd_flag & ND_NFSV3)
611 nfsrv_postopattr(nd, dattr_ret, &dattr);
614 if (named.ni_startdir)
615 vrele(named.ni_startdir);
616 nfsvno_relpathbuf(&named);
618 if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) &&
619 vp->v_type != VDIR && vp->v_type != VLNK)
621 * Only allow lookup of VDIR and VLNK for traversal of
622 * non-exported volumes during NFSv4 mounting.
624 nd->nd_repstat = ENOENT;
625 if (nd->nd_repstat == 0)
626 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
627 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
628 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
629 if (vpp != NULL && nd->nd_repstat == 0)
634 if (nd->nd_flag & ND_NFSV3)
635 dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p, 0,
639 if (nd->nd_repstat) {
640 if (nd->nd_flag & ND_NFSV3)
641 nfsrv_postopattr(nd, dattr_ret, &dattr);
644 if (nd->nd_flag & ND_NFSV2) {
645 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
646 nfsrv_fillattr(nd, &nva);
647 } else if (nd->nd_flag & ND_NFSV3) {
648 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
649 nfsrv_postopattr(nd, 0, &nva);
650 nfsrv_postopattr(nd, dattr_ret, &dattr);
654 NFSEXITCODE2(error, nd);
659 * nfs readlink service
662 nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
663 vnode_t vp, __unused struct nfsexstuff *exp)
666 struct mbuf *mp = NULL, *mpend = NULL;
669 struct thread *p = curthread;
672 if (nd->nd_repstat) {
673 nfsrv_postopattr(nd, getret, &nva);
676 if (vnode_vtype(vp) != VLNK) {
677 if (nd->nd_flag & ND_NFSV2)
678 nd->nd_repstat = ENXIO;
680 nd->nd_repstat = EINVAL;
682 if (nd->nd_repstat == 0) {
683 if ((nd->nd_flag & ND_EXTPG) != 0)
684 nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred,
685 nd->nd_maxextsiz, p, &mp, &mpend, &len);
687 nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred,
688 0, p, &mp, &mpend, &len);
690 if (nd->nd_flag & ND_NFSV3)
691 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
693 if (nd->nd_flag & ND_NFSV3)
694 nfsrv_postopattr(nd, getret, &nva);
697 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
698 *tl = txdr_unsigned(len);
700 nd->nd_mb->m_next = mp;
702 if ((mpend->m_flags & M_EXTPG) != 0) {
703 nd->nd_bextpg = mpend->m_epg_npgs - 1;
704 nd->nd_bpos = (char *)(void *)
705 PHYS_TO_DMAP(mpend->m_epg_pa[nd->nd_bextpg]);
706 off = (nd->nd_bextpg == 0) ? mpend->m_epg_1st_off : 0;
707 nd->nd_bpos += off + mpend->m_epg_last_len;
708 nd->nd_bextpgsiz = PAGE_SIZE - mpend->m_epg_last_len -
711 nd->nd_bpos = mtod(mpend, char *) + mpend->m_len;
723 nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
724 vnode_t vp, struct nfsexstuff *exp)
727 int error = 0, cnt, getret = 1, gotproxystateid, reqlen, eof = 0;
728 struct mbuf *m2, *m3;
731 struct nfsstate st, *stp = &st;
732 struct nfslock lo, *lop = &lo;
733 nfsv4stateid_t stateid;
735 struct thread *p = curthread;
738 if (nd->nd_repstat) {
739 nfsrv_postopattr(nd, getret, &nva);
742 if (nd->nd_flag & ND_NFSV2) {
743 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
744 off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
745 reqlen = fxdr_unsigned(int, *tl);
746 } else if (nd->nd_flag & ND_NFSV3) {
747 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
748 off = fxdr_hyper(tl);
750 reqlen = fxdr_unsigned(int, *tl);
752 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
753 reqlen = fxdr_unsigned(int, *(tl + 6));
755 if (reqlen > NFS_SRVMAXDATA(nd)) {
756 reqlen = NFS_SRVMAXDATA(nd);
757 } else if (reqlen < 0) {
762 if (nd->nd_flag & ND_NFSV4) {
763 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
764 lop->lo_flags = NFSLCK_READ;
765 stp->ls_ownerlen = 0;
767 stp->ls_uid = nd->nd_cred->cr_uid;
768 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
769 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
770 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
771 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
772 if ((nd->nd_flag & ND_NFSV41) != 0)
773 clientid.qval = nd->nd_clientid.qval;
774 else if (nd->nd_clientid.qval != clientid.qval)
775 printf("EEK1 multiple clids\n");
777 if ((nd->nd_flag & ND_NFSV41) != 0)
778 printf("EEK! no clientid from session\n");
779 nd->nd_flag |= ND_IMPLIEDCLID;
780 nd->nd_clientid.qval = clientid.qval;
782 stp->ls_stateid.other[2] = *tl++;
784 * Don't allow the client to use a special stateid for a DS op.
786 if ((nd->nd_flag & ND_DSSERVER) != 0 &&
787 ((stp->ls_stateid.other[0] == 0x0 &&
788 stp->ls_stateid.other[1] == 0x0 &&
789 stp->ls_stateid.other[2] == 0x0) ||
790 (stp->ls_stateid.other[0] == 0xffffffff &&
791 stp->ls_stateid.other[1] == 0xffffffff &&
792 stp->ls_stateid.other[2] == 0xffffffff) ||
793 stp->ls_stateid.seqid != 0))
794 nd->nd_repstat = NFSERR_BADSTATEID;
795 /* However, allow the proxy stateid. */
796 if (stp->ls_stateid.seqid == 0xffffffff &&
797 stp->ls_stateid.other[0] == 0x55555555 &&
798 stp->ls_stateid.other[1] == 0x55555555 &&
799 stp->ls_stateid.other[2] == 0x55555555)
801 off = fxdr_hyper(tl);
804 lop->lo_end = off + reqlen;
806 * Paranoia, just in case it wraps around.
808 if (lop->lo_end < off)
809 lop->lo_end = NFS64BITSSET;
811 if (vnode_vtype(vp) != VREG) {
812 if (nd->nd_flag & ND_NFSV3)
813 nd->nd_repstat = EINVAL;
815 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
818 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
820 nd->nd_repstat = getret;
821 if (!nd->nd_repstat &&
822 (nva.na_uid != nd->nd_cred->cr_uid ||
823 NFSVNO_EXSTRICTACCESS(exp))) {
824 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
826 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
828 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
829 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
830 NFSACCCHK_VPISLOCKED, NULL);
833 * DS reads are marked by ND_DSSERVER or use the proxy special
836 if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) ==
837 ND_NFSV4 && gotproxystateid == 0)
838 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
839 &stateid, exp, nd, p);
840 if (nd->nd_repstat) {
842 if (nd->nd_flag & ND_NFSV3)
843 nfsrv_postopattr(nd, getret, &nva);
846 if (off >= nva.na_size) {
849 } else if (reqlen == 0)
851 else if ((off + reqlen) >= nva.na_size) {
852 cnt = nva.na_size - off;
859 * If cnt > MCLBYTES and the reply will not be saved, use
860 * ext_pgs mbufs for TLS.
861 * For NFSv4.0, we do not know for sure if the reply will
862 * be saved, so do not use ext_pgs mbufs for NFSv4.0.
863 * Always use ext_pgs mbufs if ND_EXTPG is set.
865 if ((nd->nd_flag & ND_EXTPG) != 0 || (cnt > MCLBYTES &&
866 (nd->nd_flag & (ND_TLS | ND_SAVEREPLY)) == ND_TLS &&
867 (nd->nd_flag & (ND_NFSV4 | ND_NFSV41)) != ND_NFSV4))
868 nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred,
869 nd->nd_maxextsiz, p, &m3, &m2);
871 nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred,
873 if (!(nd->nd_flag & ND_NFSV4)) {
874 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
876 nd->nd_repstat = getret;
878 if (nd->nd_repstat) {
882 if (nd->nd_flag & ND_NFSV3)
883 nfsrv_postopattr(nd, getret, &nva);
888 if (nd->nd_flag & ND_NFSV2) {
889 nfsrv_fillattr(nd, &nva);
890 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
892 if (nd->nd_flag & ND_NFSV3) {
893 nfsrv_postopattr(nd, getret, &nva);
894 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
895 *tl++ = txdr_unsigned(cnt);
897 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
901 *tl++ = newnfs_false;
903 *tl = txdr_unsigned(cnt);
905 nd->nd_mb->m_next = m3;
907 if ((m2->m_flags & M_EXTPG) != 0) {
908 nd->nd_flag |= ND_EXTPG;
909 nd->nd_bextpg = m2->m_epg_npgs - 1;
910 nd->nd_bpos = (char *)(void *)
911 PHYS_TO_DMAP(m2->m_epg_pa[nd->nd_bextpg]);
912 poff = (nd->nd_bextpg == 0) ? m2->m_epg_1st_off : 0;
913 nd->nd_bpos += poff + m2->m_epg_last_len;
914 nd->nd_bextpgsiz = PAGE_SIZE - m2->m_epg_last_len -
917 nd->nd_bpos = mtod(m2, char *) + m2->m_len;
925 NFSEXITCODE2(error, nd);
933 nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
934 vnode_t vp, struct nfsexstuff *exp)
937 struct nfsvattr nva, forat;
938 int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
939 int gotproxystateid, stable = NFSWRITE_FILESYNC;
941 struct nfsstate st, *stp = &st;
942 struct nfslock lo, *lop = &lo;
943 nfsv4stateid_t stateid;
945 nfsattrbit_t attrbits;
946 struct thread *p = curthread;
948 if (nd->nd_repstat) {
949 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
953 if (nd->nd_flag & ND_NFSV2) {
954 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
955 off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
957 retlen = len = fxdr_unsigned(int32_t, *tl);
958 } else if (nd->nd_flag & ND_NFSV3) {
959 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
960 off = fxdr_hyper(tl);
962 stable = fxdr_unsigned(int, *tl++);
963 retlen = len = fxdr_unsigned(int32_t, *tl);
965 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
966 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
967 lop->lo_flags = NFSLCK_WRITE;
968 stp->ls_ownerlen = 0;
970 stp->ls_uid = nd->nd_cred->cr_uid;
971 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
972 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
973 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
974 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
975 if ((nd->nd_flag & ND_NFSV41) != 0)
976 clientid.qval = nd->nd_clientid.qval;
977 else if (nd->nd_clientid.qval != clientid.qval)
978 printf("EEK2 multiple clids\n");
980 if ((nd->nd_flag & ND_NFSV41) != 0)
981 printf("EEK! no clientid from session\n");
982 nd->nd_flag |= ND_IMPLIEDCLID;
983 nd->nd_clientid.qval = clientid.qval;
985 stp->ls_stateid.other[2] = *tl++;
987 * Don't allow the client to use a special stateid for a DS op.
989 if ((nd->nd_flag & ND_DSSERVER) != 0 &&
990 ((stp->ls_stateid.other[0] == 0x0 &&
991 stp->ls_stateid.other[1] == 0x0 &&
992 stp->ls_stateid.other[2] == 0x0) ||
993 (stp->ls_stateid.other[0] == 0xffffffff &&
994 stp->ls_stateid.other[1] == 0xffffffff &&
995 stp->ls_stateid.other[2] == 0xffffffff) ||
996 stp->ls_stateid.seqid != 0))
997 nd->nd_repstat = NFSERR_BADSTATEID;
998 /* However, allow the proxy stateid. */
999 if (stp->ls_stateid.seqid == 0xffffffff &&
1000 stp->ls_stateid.other[0] == 0x55555555 &&
1001 stp->ls_stateid.other[1] == 0x55555555 &&
1002 stp->ls_stateid.other[2] == 0x55555555)
1003 gotproxystateid = 1;
1004 off = fxdr_hyper(tl);
1005 lop->lo_first = off;
1007 stable = fxdr_unsigned(int, *tl++);
1008 retlen = len = fxdr_unsigned(int32_t, *tl);
1009 lop->lo_end = off + len;
1011 * Paranoia, just in case it wraps around, which shouldn't
1012 * ever happen anyhow.
1014 if (lop->lo_end < lop->lo_first)
1015 lop->lo_end = NFS64BITSSET;
1018 if (retlen > NFS_SRVMAXIO || retlen < 0)
1019 nd->nd_repstat = EIO;
1020 if (vnode_vtype(vp) != VREG && !nd->nd_repstat) {
1021 if (nd->nd_flag & ND_NFSV3)
1022 nd->nd_repstat = EINVAL;
1024 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
1027 NFSZERO_ATTRBIT(&attrbits);
1028 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
1029 forat_ret = nfsvno_getattr(vp, &forat, nd, p, 1, &attrbits);
1030 if (!nd->nd_repstat)
1031 nd->nd_repstat = forat_ret;
1032 if (!nd->nd_repstat &&
1033 (forat.na_uid != nd->nd_cred->cr_uid ||
1034 NFSVNO_EXSTRICTACCESS(exp)))
1035 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
1036 nd->nd_cred, exp, p,
1037 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
1039 * DS reads are marked by ND_DSSERVER or use the proxy special
1042 if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) ==
1043 ND_NFSV4 && gotproxystateid == 0)
1044 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
1045 &stateid, exp, nd, p);
1046 if (nd->nd_repstat) {
1048 if (nd->nd_flag & ND_NFSV3)
1049 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
1054 * For NFS Version 2, it is not obvious what a write of zero length
1055 * should do, but I might as well be consistent with Version 3,
1056 * which is to return ok so long as there are no permission problems.
1059 nd->nd_repstat = nfsvno_write(vp, off, retlen, &stable,
1060 nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
1061 error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
1065 if (nd->nd_flag & ND_NFSV4)
1068 aftat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
1070 if (!nd->nd_repstat)
1071 nd->nd_repstat = aftat_ret;
1072 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1073 if (nd->nd_flag & ND_NFSV3)
1074 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
1077 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1078 *tl++ = txdr_unsigned(retlen);
1080 * If nfs_async is set, then pretend the write was FILESYNC.
1081 * Warning: Doing this violates RFC1813 and runs a risk
1082 * of data written by a client being lost when the server
1085 if (stable == NFSWRITE_UNSTABLE && nfs_async == 0)
1086 *tl++ = txdr_unsigned(stable);
1088 *tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
1090 * Actually, there is no need to txdr these fields,
1091 * but it may make the values more human readable,
1092 * for debugging purposes.
1094 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
1095 *tl = txdr_unsigned(nfsboottime.tv_usec);
1096 } else if (!nd->nd_repstat)
1097 nfsrv_fillattr(nd, &nva);
1100 NFSEXITCODE2(0, nd);
1104 NFSEXITCODE2(error, nd);
1109 * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
1110 * now does a truncate to 0 length via. setattr if it already exists
1111 * The core creation routine has been extracted out into nfsrv_creatsub(),
1112 * so it can also be used by nfsrv_open() for V4.
1115 nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
1116 vnode_t dp, struct nfsexstuff *exp)
1118 struct nfsvattr nva, dirfor, diraft;
1119 struct nfsv2_sattr *sp;
1120 struct nameidata named;
1122 int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
1123 int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
1125 vnode_t vp = NULL, dirp = NULL;
1130 int32_t cverf[2], tverf[2] = { 0, 0 };
1131 struct thread *p = curthread;
1133 if (nd->nd_repstat) {
1134 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1137 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1138 LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
1139 nfsvno_setpathbuf(&named, &bufp, &hashp);
1140 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1143 if (!nd->nd_repstat) {
1144 NFSVNO_ATTRINIT(&nva);
1145 if (nd->nd_flag & ND_NFSV2) {
1146 NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1147 vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
1150 NFSVNO_SETATTRVAL(&nva, type, vtyp);
1151 NFSVNO_SETATTRVAL(&nva, mode,
1152 nfstov_mode(sp->sa_mode));
1153 switch (nva.na_type) {
1155 tsize = fxdr_unsigned(int32_t, sp->sa_size);
1157 NFSVNO_SETATTRVAL(&nva, size,
1163 rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
1169 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1170 how = fxdr_unsigned(int, *tl);
1172 case NFSCREATE_GUARDED:
1173 case NFSCREATE_UNCHECKED:
1174 error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
1178 case NFSCREATE_EXCLUSIVE:
1179 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
1185 NFSVNO_SETATTRVAL(&nva, type, VREG);
1188 if (nd->nd_repstat) {
1189 nfsvno_relpathbuf(&named);
1190 if (nd->nd_flag & ND_NFSV3) {
1191 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 1,
1193 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1200 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1202 if (nd->nd_flag & ND_NFSV2) {
1206 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1210 if (nd->nd_repstat) {
1211 if (nd->nd_flag & ND_NFSV3)
1212 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1219 if (!(nd->nd_flag & ND_NFSV2)) {
1221 case NFSCREATE_GUARDED:
1223 nd->nd_repstat = EEXIST;
1225 case NFSCREATE_UNCHECKED:
1227 case NFSCREATE_EXCLUSIVE:
1228 if (named.ni_vp == NULL)
1229 NFSVNO_SETATTRVAL(&nva, mode, 0);
1235 * Iff doesn't exist, create it
1236 * otherwise just truncate to 0 length
1237 * should I set the mode too ?
1239 nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
1240 &exclusive_flag, cverf, rdev, exp);
1242 if (!nd->nd_repstat) {
1243 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
1244 if (!nd->nd_repstat)
1245 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
1248 if (!nd->nd_repstat) {
1249 tverf[0] = nva.na_atime.tv_sec;
1250 tverf[1] = nva.na_atime.tv_nsec;
1253 if (nd->nd_flag & ND_NFSV2) {
1254 if (!nd->nd_repstat) {
1255 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
1256 nfsrv_fillattr(nd, &nva);
1259 if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
1260 || cverf[1] != tverf[1]))
1261 nd->nd_repstat = EEXIST;
1262 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1264 if (!nd->nd_repstat) {
1265 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
1266 nfsrv_postopattr(nd, 0, &nva);
1268 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1272 NFSEXITCODE2(0, nd);
1276 nfsvno_relpathbuf(&named);
1277 NFSEXITCODE2(error, nd);
1282 * nfs v3 mknod service (and v4 create)
1285 nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
1286 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
1288 struct nfsvattr nva, dirfor, diraft;
1290 struct nameidata named;
1291 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1292 u_int32_t major, minor;
1293 enum vtype vtyp = VNON;
1294 nfstype nfs4type = NFNON;
1295 vnode_t vp, dirp = NULL;
1296 nfsattrbit_t attrbits;
1297 char *bufp = NULL, *pathcp = NULL;
1298 u_long *hashp, cnflags;
1299 NFSACL_T *aclp = NULL;
1300 struct thread *p = curthread;
1302 NFSVNO_ATTRINIT(&nva);
1303 cnflags = (LOCKPARENT | SAVESTART);
1304 if (nd->nd_repstat) {
1305 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1308 #ifdef NFS4_ACL_EXTATTR_NAME
1309 aclp = acl_alloc(M_WAITOK);
1314 * For V4, the creation stuff is here, Yuck!
1316 if (nd->nd_flag & ND_NFSV4) {
1317 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1318 vtyp = nfsv34tov_type(*tl);
1319 nfs4type = fxdr_unsigned(nfstype, *tl);
1322 error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
1329 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1330 major = fxdr_unsigned(u_int32_t, *tl++);
1331 minor = fxdr_unsigned(u_int32_t, *tl);
1332 nva.na_rdev = NFSMAKEDEV(major, minor);
1338 cnflags = (LOCKPARENT | SAVENAME);
1341 nd->nd_repstat = NFSERR_BADTYPE;
1343 #ifdef NFS4_ACL_EXTATTR_NAME
1349 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags | NOCACHE);
1350 nfsvno_setpathbuf(&named, &bufp, &hashp);
1351 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1354 if (!nd->nd_repstat) {
1355 if (nd->nd_flag & ND_NFSV3) {
1356 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1357 vtyp = nfsv34tov_type(*tl);
1359 error = nfsrv_sattr(nd, NULL, &nva, &attrbits, aclp, p);
1363 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
1364 (vtyp == VCHR || vtyp == VBLK)) {
1365 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1366 major = fxdr_unsigned(u_int32_t, *tl++);
1367 minor = fxdr_unsigned(u_int32_t, *tl);
1368 nva.na_rdev = NFSMAKEDEV(major, minor);
1372 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
1373 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
1374 if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
1375 dirfor.na_gid == nva.na_gid)
1376 NFSVNO_UNSET(&nva, gid);
1377 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
1379 if (nd->nd_repstat) {
1381 #ifdef NFS4_ACL_EXTATTR_NAME
1384 nfsvno_relpathbuf(&named);
1386 free(pathcp, M_TEMP);
1387 if (nd->nd_flag & ND_NFSV3)
1388 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1394 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
1395 * in va_mode, so we'll have to set a default here.
1397 if (NFSVNO_NOTSETMODE(&nva)) {
1405 named.ni_cnd.cn_flags |= WILLBEDIR;
1406 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1407 if (nd->nd_repstat) {
1409 if (nd->nd_flag & ND_NFSV3)
1410 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd,
1414 #ifdef NFS4_ACL_EXTATTR_NAME
1417 if (nd->nd_flag & ND_NFSV3)
1418 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1423 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
1425 if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
1427 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
1428 &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
1430 #ifdef NFS4_ACL_EXTATTR_NAME
1434 } else if (vtyp == VLNK) {
1435 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1436 &dirfor, &diraft, &diraft_ret, &attrbits,
1437 aclp, p, exp, pathcp, pathlen);
1438 #ifdef NFS4_ACL_EXTATTR_NAME
1441 free(pathcp, M_TEMP);
1446 nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
1447 if (!nd->nd_repstat) {
1449 nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
1450 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1451 if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
1452 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
1454 if (vpp != NULL && nd->nd_repstat == 0) {
1461 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1463 if (!nd->nd_repstat) {
1464 if (nd->nd_flag & ND_NFSV3) {
1465 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1466 nfsrv_postopattr(nd, 0, &nva);
1468 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1469 *tl++ = newnfs_false;
1470 txdr_hyper(dirfor.na_filerev, tl);
1472 txdr_hyper(diraft.na_filerev, tl);
1473 (void) nfsrv_putattrbit(nd, &attrbits);
1476 if (nd->nd_flag & ND_NFSV3)
1477 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1478 #ifdef NFS4_ACL_EXTATTR_NAME
1483 NFSEXITCODE2(0, nd);
1487 #ifdef NFS4_ACL_EXTATTR_NAME
1491 nfsvno_relpathbuf(&named);
1493 free(pathcp, M_TEMP);
1495 NFSEXITCODE2(error, nd);
1500 * nfs remove service
1503 nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
1504 vnode_t dp, struct nfsexstuff *exp)
1506 struct nameidata named;
1508 int error = 0, dirfor_ret = 1, diraft_ret = 1;
1509 vnode_t dirp = NULL;
1510 struct nfsvattr dirfor, diraft;
1513 struct thread *p = curthread;
1515 if (nd->nd_repstat) {
1516 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1519 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
1520 LOCKPARENT | LOCKLEAF);
1521 nfsvno_setpathbuf(&named, &bufp, &hashp);
1522 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1525 nfsvno_relpathbuf(&named);
1528 if (!nd->nd_repstat) {
1529 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1532 nfsvno_relpathbuf(&named);
1535 if (!(nd->nd_flag & ND_NFSV2)) {
1536 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1543 if (!nd->nd_repstat) {
1544 if (nd->nd_flag & ND_NFSV4) {
1545 if (vnode_vtype(named.ni_vp) == VDIR)
1546 nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
1547 nd->nd_cred, p, exp);
1549 nd->nd_repstat = nfsvno_removesub(&named, 1,
1550 nd->nd_cred, p, exp);
1551 } else if (nd->nd_procnum == NFSPROC_RMDIR) {
1552 nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
1553 nd->nd_cred, p, exp);
1555 nd->nd_repstat = nfsvno_removesub(&named, 0,
1556 nd->nd_cred, p, exp);
1559 if (!(nd->nd_flag & ND_NFSV2)) {
1561 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0,
1565 if (nd->nd_flag & ND_NFSV3) {
1566 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1568 } else if (!nd->nd_repstat) {
1569 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1570 *tl++ = newnfs_false;
1571 txdr_hyper(dirfor.na_filerev, tl);
1573 txdr_hyper(diraft.na_filerev, tl);
1578 NFSEXITCODE2(error, nd);
1583 * nfs rename service
1586 nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
1587 vnode_t dp, vnode_t todp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
1590 int error = 0, fdirfor_ret = 1, fdiraft_ret = 1;
1591 int tdirfor_ret = 1, tdiraft_ret = 1;
1592 struct nameidata fromnd, tond;
1593 vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
1594 struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
1595 struct nfsexstuff tnes;
1597 char *bufp, *tbufp = NULL;
1600 struct thread *p = curthread;
1602 if (nd->nd_repstat) {
1603 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1604 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1607 if (!(nd->nd_flag & ND_NFSV2))
1608 fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd, p, 1, NULL);
1609 tond.ni_cnd.cn_nameiop = 0;
1610 tond.ni_startdir = NULL;
1611 NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART);
1612 nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
1613 error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
1618 nfsvno_relpathbuf(&fromnd);
1622 * Unlock dp in this code section, so it is unlocked before
1623 * tdp gets locked. This avoids a potential LOR if tdp is the
1624 * parent directory of dp.
1626 if (nd->nd_flag & ND_NFSV4) {
1631 /* Might lock tdp. */
1632 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 0,
1635 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1,
1640 tfh.nfsrvfh_len = 0;
1641 error = nfsrv_mtofh(nd, &tfh);
1643 error = nfsvno_getfh(dp, &fh, p);
1646 /* todp is always NULL except NFSv4 */
1647 nfsvno_relpathbuf(&fromnd);
1651 /* If this is the same file handle, just VREF() the vnode. */
1652 if (tfh.nfsrvfh_len == NFSX_MYFH &&
1653 !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
1657 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1,
1662 nd->nd_cred->cr_uid = nd->nd_saveduid;
1663 nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
1664 0); /* Locks tdp. */
1666 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd,
1672 NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
1673 nfsvno_setpathbuf(&tond, &tbufp, &hashp);
1674 if (!nd->nd_repstat) {
1675 error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
1680 nfsvno_relpathbuf(&fromnd);
1681 nfsvno_relpathbuf(&tond);
1685 if (nd->nd_repstat) {
1686 if (nd->nd_flag & ND_NFSV3) {
1687 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1689 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1695 nfsvno_relpathbuf(&fromnd);
1696 nfsvno_relpathbuf(&tond);
1701 * Done parsing, now down to business.
1703 nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, p, &fdirp);
1704 if (nd->nd_repstat) {
1705 if (nd->nd_flag & ND_NFSV3) {
1706 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1708 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1715 nfsvno_relpathbuf(&tond);
1718 if (vnode_vtype(fromnd.ni_vp) == VDIR)
1719 tond.ni_cnd.cn_flags |= WILLBEDIR;
1720 nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
1721 nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
1722 nd->nd_flag, nd->nd_cred, p);
1724 fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd, p, 0, NULL);
1726 tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd, p, 0, NULL);
1731 if (nd->nd_flag & ND_NFSV3) {
1732 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1733 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1734 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1735 NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
1736 *tl++ = newnfs_false;
1737 txdr_hyper(fdirfor.na_filerev, tl);
1739 txdr_hyper(fdiraft.na_filerev, tl);
1741 *tl++ = newnfs_false;
1742 txdr_hyper(tdirfor.na_filerev, tl);
1744 txdr_hyper(tdiraft.na_filerev, tl);
1748 NFSEXITCODE2(error, nd);
1756 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
1757 vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
1759 struct nameidata named;
1761 int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
1762 vnode_t dirp = NULL, dp = NULL;
1763 struct nfsvattr dirfor, diraft, at;
1764 struct nfsexstuff tnes;
1768 struct thread *p = curthread;
1770 if (nd->nd_repstat) {
1771 nfsrv_postopattr(nd, getret, &at);
1772 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1776 if (vnode_vtype(vp) == VDIR) {
1777 if (nd->nd_flag & ND_NFSV4)
1778 nd->nd_repstat = NFSERR_ISDIR;
1780 nd->nd_repstat = NFSERR_INVAL;
1784 if (!nd->nd_repstat) {
1785 if (nd->nd_flag & ND_NFSV4) {
1789 error = nfsrv_mtofh(nd, &dfh);
1792 /* tovp is always NULL unless NFSv4 */
1795 nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0);
1800 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1801 LOCKPARENT | SAVENAME | NOCACHE);
1802 if (!nd->nd_repstat) {
1803 nfsvno_setpathbuf(&named, &bufp, &hashp);
1804 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1809 nfsvno_relpathbuf(&named);
1812 if (!nd->nd_repstat) {
1813 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
1818 nfsvno_relpathbuf(&named);
1822 if (nd->nd_flag & ND_NFSV2) {
1826 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1830 if (!nd->nd_repstat)
1831 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
1832 if (nd->nd_flag & ND_NFSV3)
1833 getret = nfsvno_getattr(vp, &at, nd, p, 0, NULL);
1835 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1839 if (nd->nd_flag & ND_NFSV3) {
1840 nfsrv_postopattr(nd, getret, &at);
1841 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1842 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1843 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1844 *tl++ = newnfs_false;
1845 txdr_hyper(dirfor.na_filerev, tl);
1847 txdr_hyper(diraft.na_filerev, tl);
1851 NFSEXITCODE2(error, nd);
1856 * nfs symbolic link service
1859 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1860 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
1862 struct nfsvattr nva, dirfor, diraft;
1863 struct nameidata named;
1864 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1865 vnode_t dirp = NULL;
1866 char *bufp, *pathcp = NULL;
1868 struct thread *p = curthread;
1870 if (nd->nd_repstat) {
1871 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1876 NFSVNO_ATTRINIT(&nva);
1877 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1878 LOCKPARENT | SAVESTART | NOCACHE);
1879 nfsvno_setpathbuf(&named, &bufp, &hashp);
1880 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1881 if (!error && !nd->nd_repstat)
1882 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
1885 nfsvno_relpathbuf(&named);
1888 if (!nd->nd_repstat) {
1889 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1892 nfsvno_relpathbuf(&named);
1894 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1900 * And call nfsrvd_symlinksub() to do the common code. It will
1901 * return EBADRPC upon a parsing error, 0 otherwise.
1903 if (!nd->nd_repstat) {
1905 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1907 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1908 &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
1910 } else if (dirp != NULL) {
1911 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
1915 free(pathcp, M_TEMP);
1917 if (nd->nd_flag & ND_NFSV3) {
1918 if (!nd->nd_repstat) {
1919 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1920 nfsrv_postopattr(nd, 0, &nva);
1922 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1926 NFSEXITCODE2(error, nd);
1931 * Common code for creating a symbolic link.
1934 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
1935 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1936 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1937 int *diraft_retp, nfsattrbit_t *attrbitp,
1938 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
1943 nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
1944 !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
1945 if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
1946 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
1947 if (nd->nd_flag & ND_NFSV3) {
1948 nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
1949 if (!nd->nd_repstat)
1950 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
1951 nvap, nd, p, 1, NULL);
1953 if (vpp != NULL && nd->nd_repstat == 0) {
1954 NFSVOPUNLOCK(ndp->ni_vp);
1960 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL);
1963 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1964 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1965 *tl++ = newnfs_false;
1966 txdr_hyper(dirforp->na_filerev, tl);
1968 txdr_hyper(diraftp->na_filerev, tl);
1969 (void) nfsrv_putattrbit(nd, attrbitp);
1972 NFSEXITCODE2(0, nd);
1979 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
1980 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
1982 struct nfsvattr nva, dirfor, diraft;
1983 struct nameidata named;
1985 int error = 0, dirfor_ret = 1, diraft_ret = 1;
1986 vnode_t dirp = NULL;
1989 struct thread *p = curthread;
1991 if (nd->nd_repstat) {
1992 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1995 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1996 LOCKPARENT | SAVENAME | NOCACHE);
1997 nfsvno_setpathbuf(&named, &bufp, &hashp);
1998 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2001 if (!nd->nd_repstat) {
2002 NFSVNO_ATTRINIT(&nva);
2003 if (nd->nd_flag & ND_NFSV3) {
2004 error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
2008 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2009 nva.na_mode = nfstov_mode(*tl++);
2012 if (!nd->nd_repstat) {
2013 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
2016 nfsvno_relpathbuf(&named);
2018 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
2022 if (nd->nd_repstat) {
2024 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
2028 if (nd->nd_flag & ND_NFSV3)
2029 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
2034 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
2037 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
2039 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
2040 &diraft_ret, NULL, NULL, p, exp);
2042 if (nd->nd_flag & ND_NFSV3) {
2043 if (!nd->nd_repstat) {
2044 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
2045 nfsrv_postopattr(nd, 0, &nva);
2047 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
2048 } else if (!nd->nd_repstat) {
2049 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2050 nfsrv_fillattr(nd, &nva);
2054 NFSEXITCODE2(0, nd);
2058 nfsvno_relpathbuf(&named);
2059 NFSEXITCODE2(error, nd);
2064 * Code common to mkdir for V2,3 and 4.
2067 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
2068 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
2069 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
2070 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
2071 NFSPROC_T *p, struct nfsexstuff *exp)
2076 NFSVNO_SETATTRVAL(nvap, type, VDIR);
2077 nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
2078 nd->nd_cred, p, exp);
2079 if (!nd->nd_repstat) {
2081 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
2082 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
2083 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
2084 nd->nd_repstat = nfsvno_getattr(vp, nvap, nd, p, 1,
2086 if (vpp && !nd->nd_repstat) {
2094 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL);
2097 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
2098 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2099 *tl++ = newnfs_false;
2100 txdr_hyper(dirforp->na_filerev, tl);
2102 txdr_hyper(diraftp->na_filerev, tl);
2103 (void) nfsrv_putattrbit(nd, attrbitp);
2106 NFSEXITCODE2(0, nd);
2110 * nfs commit service
2113 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
2114 vnode_t vp, __unused struct nfsexstuff *exp)
2116 struct nfsvattr bfor, aft;
2118 int error = 0, for_ret = 1, aft_ret = 1, cnt;
2120 struct thread *p = curthread;
2122 if (nd->nd_repstat) {
2123 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
2127 /* Return NFSERR_ISDIR in NFSv4 when commit on a directory. */
2128 if (vp->v_type != VREG) {
2129 if (nd->nd_flag & ND_NFSV3)
2130 error = NFSERR_NOTSUPP;
2132 error = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_INVAL;
2135 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2138 * XXX At this time VOP_FSYNC() does not accept offset and byte
2139 * count parameters, so these arguments are useless (someday maybe).
2141 off = fxdr_hyper(tl);
2143 cnt = fxdr_unsigned(int, *tl);
2144 if (nd->nd_flag & ND_NFSV3)
2145 for_ret = nfsvno_getattr(vp, &bfor, nd, p, 1, NULL);
2146 nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
2147 if (nd->nd_flag & ND_NFSV3) {
2148 aft_ret = nfsvno_getattr(vp, &aft, nd, p, 1, NULL);
2149 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
2152 if (!nd->nd_repstat) {
2153 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2154 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
2155 *tl = txdr_unsigned(nfsboottime.tv_usec);
2159 NFSEXITCODE2(0, nd);
2163 NFSEXITCODE2(error, nd);
2168 * nfs statfs service
2171 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
2172 vnode_t vp, __unused struct nfsexstuff *exp)
2179 struct thread *p = curthread;
2182 if (nd->nd_repstat) {
2183 nfsrv_postopattr(nd, getret, &at);
2186 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2187 nd->nd_repstat = nfsvno_statfs(vp, sf);
2188 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2190 if (nd->nd_flag & ND_NFSV3)
2191 nfsrv_postopattr(nd, getret, &at);
2194 if (nd->nd_flag & ND_NFSV2) {
2195 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
2196 *tl++ = txdr_unsigned(NFS_V2MAXDATA);
2197 *tl++ = txdr_unsigned(sf->f_bsize);
2198 *tl++ = txdr_unsigned(sf->f_blocks);
2199 *tl++ = txdr_unsigned(sf->f_bfree);
2200 *tl = txdr_unsigned(sf->f_bavail);
2202 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
2203 tval = (u_quad_t)sf->f_blocks;
2204 tval *= (u_quad_t)sf->f_bsize;
2205 txdr_hyper(tval, tl); tl += 2;
2206 tval = (u_quad_t)sf->f_bfree;
2207 tval *= (u_quad_t)sf->f_bsize;
2208 txdr_hyper(tval, tl); tl += 2;
2209 tval = (u_quad_t)sf->f_bavail;
2210 tval *= (u_quad_t)sf->f_bsize;
2211 txdr_hyper(tval, tl); tl += 2;
2212 tval = (u_quad_t)sf->f_files;
2213 txdr_hyper(tval, tl); tl += 2;
2214 tval = (u_quad_t)sf->f_ffree;
2215 txdr_hyper(tval, tl); tl += 2;
2216 tval = (u_quad_t)sf->f_ffree;
2217 txdr_hyper(tval, tl); tl += 2;
2223 NFSEXITCODE2(0, nd);
2228 * nfs fsinfo service
2231 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
2232 vnode_t vp, __unused struct nfsexstuff *exp)
2235 struct nfsfsinfo fs;
2238 struct thread *p = curthread;
2240 if (nd->nd_repstat) {
2241 nfsrv_postopattr(nd, getret, &at);
2244 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2245 nfsvno_getfs(&fs, isdgram);
2247 nfsrv_postopattr(nd, getret, &at);
2248 NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
2249 *tl++ = txdr_unsigned(fs.fs_rtmax);
2250 *tl++ = txdr_unsigned(fs.fs_rtpref);
2251 *tl++ = txdr_unsigned(fs.fs_rtmult);
2252 *tl++ = txdr_unsigned(fs.fs_wtmax);
2253 *tl++ = txdr_unsigned(fs.fs_wtpref);
2254 *tl++ = txdr_unsigned(fs.fs_wtmult);
2255 *tl++ = txdr_unsigned(fs.fs_dtpref);
2256 txdr_hyper(fs.fs_maxfilesize, tl);
2258 txdr_nfsv3time(&fs.fs_timedelta, tl);
2260 *tl = txdr_unsigned(fs.fs_properties);
2263 NFSEXITCODE2(0, nd);
2268 * nfs pathconf service
2271 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
2272 vnode_t vp, __unused struct nfsexstuff *exp)
2274 struct nfsv3_pathconf *pc;
2276 long linkmax, namemax, chownres, notrunc;
2278 struct thread *p = curthread;
2280 if (nd->nd_repstat) {
2281 nfsrv_postopattr(nd, getret, &at);
2284 nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
2286 if (!nd->nd_repstat)
2287 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
2289 if (!nd->nd_repstat)
2290 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
2291 &chownres, nd->nd_cred, p);
2292 if (!nd->nd_repstat)
2293 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc,
2295 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2297 nfsrv_postopattr(nd, getret, &at);
2298 if (!nd->nd_repstat) {
2299 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
2300 pc->pc_linkmax = txdr_unsigned(linkmax);
2301 pc->pc_namemax = txdr_unsigned(namemax);
2302 pc->pc_notrunc = txdr_unsigned(notrunc);
2303 pc->pc_chownrestricted = txdr_unsigned(chownres);
2306 * These should probably be supported by VOP_PATHCONF(), but
2307 * until msdosfs is exportable (why would you want to?), the
2308 * Unix defaults should be ok.
2310 pc->pc_caseinsensitive = newnfs_false;
2311 pc->pc_casepreserving = newnfs_true;
2315 NFSEXITCODE2(0, nd);
2320 * nfsv4 lock service
2323 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2324 vnode_t vp, struct nfsexstuff *exp)
2328 struct nfsstate *stp = NULL;
2329 struct nfslock *lop;
2330 struct nfslockconflict cf;
2332 u_short flags = NFSLCK_LOCK, lflags;
2333 u_int64_t offset, len;
2334 nfsv4stateid_t stateid;
2336 struct thread *p = curthread;
2338 NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2339 i = fxdr_unsigned(int, *tl++);
2341 case NFSV4LOCKT_READW:
2342 flags |= NFSLCK_BLOCKING;
2343 case NFSV4LOCKT_READ:
2344 lflags = NFSLCK_READ;
2346 case NFSV4LOCKT_WRITEW:
2347 flags |= NFSLCK_BLOCKING;
2348 case NFSV4LOCKT_WRITE:
2349 lflags = NFSLCK_WRITE;
2352 nd->nd_repstat = NFSERR_BADXDR;
2355 if (*tl++ == newnfs_true)
2356 flags |= NFSLCK_RECLAIM;
2357 offset = fxdr_hyper(tl);
2359 len = fxdr_hyper(tl);
2361 if (*tl == newnfs_true)
2362 flags |= NFSLCK_OPENTOLOCK;
2363 if (flags & NFSLCK_OPENTOLOCK) {
2364 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2365 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2366 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2367 nd->nd_repstat = NFSERR_BADXDR;
2370 stp = malloc(sizeof (struct nfsstate) + i,
2371 M_NFSDSTATE, M_WAITOK);
2372 stp->ls_ownerlen = i;
2373 stp->ls_op = nd->nd_rp;
2374 stp->ls_seq = fxdr_unsigned(int, *tl++);
2375 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2376 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2378 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2381 * For the special stateid of other all 0s and seqid == 1, set
2382 * the stateid to the current stateid, if it is set.
2384 if ((nd->nd_flag & ND_NFSV41) != 0 &&
2385 stp->ls_stateid.seqid == 1 &&
2386 stp->ls_stateid.other[0] == 0 &&
2387 stp->ls_stateid.other[1] == 0 &&
2388 stp->ls_stateid.other[2] == 0) {
2389 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2390 stp->ls_stateid = nd->nd_curstateid;
2391 stp->ls_stateid.seqid = 0;
2393 nd->nd_repstat = NFSERR_BADSTATEID;
2398 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2399 clientid.lval[0] = *tl++;
2400 clientid.lval[1] = *tl++;
2401 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2402 if ((nd->nd_flag & ND_NFSV41) != 0)
2403 clientid.qval = nd->nd_clientid.qval;
2404 else if (nd->nd_clientid.qval != clientid.qval)
2405 printf("EEK3 multiple clids\n");
2407 if ((nd->nd_flag & ND_NFSV41) != 0)
2408 printf("EEK! no clientid from session\n");
2409 nd->nd_flag |= ND_IMPLIEDCLID;
2410 nd->nd_clientid.qval = clientid.qval;
2412 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2416 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2417 stp = malloc(sizeof (struct nfsstate),
2418 M_NFSDSTATE, M_WAITOK);
2419 stp->ls_ownerlen = 0;
2420 stp->ls_op = nd->nd_rp;
2421 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2422 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2424 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2427 * For the special stateid of other all 0s and seqid == 1, set
2428 * the stateid to the current stateid, if it is set.
2430 if ((nd->nd_flag & ND_NFSV41) != 0 &&
2431 stp->ls_stateid.seqid == 1 &&
2432 stp->ls_stateid.other[0] == 0 &&
2433 stp->ls_stateid.other[1] == 0 &&
2434 stp->ls_stateid.other[2] == 0) {
2435 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2436 stp->ls_stateid = nd->nd_curstateid;
2437 stp->ls_stateid.seqid = 0;
2439 nd->nd_repstat = NFSERR_BADSTATEID;
2444 stp->ls_seq = fxdr_unsigned(int, *tl);
2445 clientid.lval[0] = stp->ls_stateid.other[0];
2446 clientid.lval[1] = stp->ls_stateid.other[1];
2447 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2448 if ((nd->nd_flag & ND_NFSV41) != 0)
2449 clientid.qval = nd->nd_clientid.qval;
2450 else if (nd->nd_clientid.qval != clientid.qval)
2451 printf("EEK4 multiple clids\n");
2453 if ((nd->nd_flag & ND_NFSV41) != 0)
2454 printf("EEK! no clientid from session\n");
2455 nd->nd_flag |= ND_IMPLIEDCLID;
2456 nd->nd_clientid.qval = clientid.qval;
2459 lop = malloc(sizeof (struct nfslock),
2460 M_NFSDLOCK, M_WAITOK);
2461 lop->lo_first = offset;
2462 if (len == NFS64BITSSET) {
2463 lop->lo_end = NFS64BITSSET;
2465 lop->lo_end = offset + len;
2466 if (lop->lo_end <= lop->lo_first)
2467 nd->nd_repstat = NFSERR_INVAL;
2469 lop->lo_flags = lflags;
2470 stp->ls_flags = flags;
2471 stp->ls_uid = nd->nd_cred->cr_uid;
2474 * Do basic access checking.
2476 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2477 if (vnode_vtype(vp) == VDIR)
2478 nd->nd_repstat = NFSERR_ISDIR;
2480 nd->nd_repstat = NFSERR_INVAL;
2482 if (!nd->nd_repstat) {
2483 if (lflags & NFSLCK_WRITE) {
2484 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
2485 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2486 NFSACCCHK_VPISLOCKED, NULL);
2488 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
2489 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2490 NFSACCCHK_VPISLOCKED, NULL);
2492 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2493 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2494 NFSACCCHK_VPISLOCKED, NULL);
2499 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
2500 * seqid# gets updated. nfsrv_lockctrl() will return the value
2501 * of nd_repstat, if it gets that far.
2503 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2504 &stateid, exp, nd, p);
2506 free(lop, M_NFSDLOCK);
2508 free(stp, M_NFSDSTATE);
2509 if (!nd->nd_repstat) {
2510 /* For NFSv4.1, set the Current StateID. */
2511 if ((nd->nd_flag & ND_NFSV41) != 0) {
2512 nd->nd_curstateid = stateid;
2513 nd->nd_flag |= ND_CURSTATEID;
2515 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2516 *tl++ = txdr_unsigned(stateid.seqid);
2517 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2518 } else if (nd->nd_repstat == NFSERR_DENIED) {
2519 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2520 txdr_hyper(cf.cl_first, tl);
2522 if (cf.cl_end == NFS64BITSSET)
2525 len = cf.cl_end - cf.cl_first;
2526 txdr_hyper(len, tl);
2528 if (cf.cl_flags == NFSLCK_WRITE)
2529 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2531 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2532 *tl++ = stateid.other[0];
2533 *tl = stateid.other[1];
2534 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2537 NFSEXITCODE2(0, nd);
2542 free(stp, M_NFSDSTATE);
2543 NFSEXITCODE2(error, nd);
2548 * nfsv4 lock test service
2551 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2552 vnode_t vp, struct nfsexstuff *exp)
2556 struct nfsstate *stp = NULL;
2557 struct nfslock lo, *lop = &lo;
2558 struct nfslockconflict cf;
2560 nfsv4stateid_t stateid;
2563 struct thread *p = curthread;
2565 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2566 i = fxdr_unsigned(int, *(tl + 7));
2567 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2568 nd->nd_repstat = NFSERR_BADXDR;
2571 stp = malloc(sizeof (struct nfsstate) + i,
2572 M_NFSDSTATE, M_WAITOK);
2573 stp->ls_ownerlen = i;
2575 stp->ls_flags = NFSLCK_TEST;
2576 stp->ls_uid = nd->nd_cred->cr_uid;
2577 i = fxdr_unsigned(int, *tl++);
2579 case NFSV4LOCKT_READW:
2580 stp->ls_flags |= NFSLCK_BLOCKING;
2581 case NFSV4LOCKT_READ:
2582 lo.lo_flags = NFSLCK_READ;
2584 case NFSV4LOCKT_WRITEW:
2585 stp->ls_flags |= NFSLCK_BLOCKING;
2586 case NFSV4LOCKT_WRITE:
2587 lo.lo_flags = NFSLCK_WRITE;
2590 nd->nd_repstat = NFSERR_BADXDR;
2593 lo.lo_first = fxdr_hyper(tl);
2595 len = fxdr_hyper(tl);
2596 if (len == NFS64BITSSET) {
2597 lo.lo_end = NFS64BITSSET;
2599 lo.lo_end = lo.lo_first + len;
2600 if (lo.lo_end <= lo.lo_first)
2601 nd->nd_repstat = NFSERR_INVAL;
2604 clientid.lval[0] = *tl++;
2605 clientid.lval[1] = *tl;
2606 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2607 if ((nd->nd_flag & ND_NFSV41) != 0)
2608 clientid.qval = nd->nd_clientid.qval;
2609 else if (nd->nd_clientid.qval != clientid.qval)
2610 printf("EEK5 multiple clids\n");
2612 if ((nd->nd_flag & ND_NFSV41) != 0)
2613 printf("EEK! no clientid from session\n");
2614 nd->nd_flag |= ND_IMPLIEDCLID;
2615 nd->nd_clientid.qval = clientid.qval;
2617 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2620 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2621 if (vnode_vtype(vp) == VDIR)
2622 nd->nd_repstat = NFSERR_ISDIR;
2624 nd->nd_repstat = NFSERR_INVAL;
2626 if (!nd->nd_repstat)
2627 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2628 &stateid, exp, nd, p);
2629 if (nd->nd_repstat) {
2630 if (nd->nd_repstat == NFSERR_DENIED) {
2631 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2632 txdr_hyper(cf.cl_first, tl);
2634 if (cf.cl_end == NFS64BITSSET)
2637 len = cf.cl_end - cf.cl_first;
2638 txdr_hyper(len, tl);
2640 if (cf.cl_flags == NFSLCK_WRITE)
2641 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2643 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2644 *tl++ = stp->ls_stateid.other[0];
2645 *tl = stp->ls_stateid.other[1];
2646 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2651 free(stp, M_NFSDSTATE);
2652 NFSEXITCODE2(0, nd);
2657 free(stp, M_NFSDSTATE);
2658 NFSEXITCODE2(error, nd);
2663 * nfsv4 unlock service
2666 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2667 vnode_t vp, struct nfsexstuff *exp)
2671 struct nfsstate *stp;
2672 struct nfslock *lop;
2674 nfsv4stateid_t stateid;
2677 struct thread *p = curthread;
2679 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2680 stp = malloc(sizeof (struct nfsstate),
2681 M_NFSDSTATE, M_WAITOK);
2682 lop = malloc(sizeof (struct nfslock),
2683 M_NFSDLOCK, M_WAITOK);
2684 stp->ls_flags = NFSLCK_UNLOCK;
2685 lop->lo_flags = NFSLCK_UNLOCK;
2686 stp->ls_op = nd->nd_rp;
2687 i = fxdr_unsigned(int, *tl++);
2689 case NFSV4LOCKT_READW:
2690 stp->ls_flags |= NFSLCK_BLOCKING;
2691 case NFSV4LOCKT_READ:
2693 case NFSV4LOCKT_WRITEW:
2694 stp->ls_flags |= NFSLCK_BLOCKING;
2695 case NFSV4LOCKT_WRITE:
2698 nd->nd_repstat = NFSERR_BADXDR;
2699 free(stp, M_NFSDSTATE);
2700 free(lop, M_NFSDLOCK);
2703 stp->ls_ownerlen = 0;
2704 stp->ls_uid = nd->nd_cred->cr_uid;
2705 stp->ls_seq = fxdr_unsigned(int, *tl++);
2706 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2707 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2709 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2712 * For the special stateid of other all 0s and seqid == 1, set the
2713 * stateid to the current stateid, if it is set.
2715 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
2716 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
2717 stp->ls_stateid.other[2] == 0) {
2718 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2719 stp->ls_stateid = nd->nd_curstateid;
2720 stp->ls_stateid.seqid = 0;
2722 nd->nd_repstat = NFSERR_BADSTATEID;
2727 lop->lo_first = fxdr_hyper(tl);
2729 len = fxdr_hyper(tl);
2730 if (len == NFS64BITSSET) {
2731 lop->lo_end = NFS64BITSSET;
2733 lop->lo_end = lop->lo_first + len;
2734 if (lop->lo_end <= lop->lo_first)
2735 nd->nd_repstat = NFSERR_INVAL;
2737 clientid.lval[0] = stp->ls_stateid.other[0];
2738 clientid.lval[1] = stp->ls_stateid.other[1];
2739 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2740 if ((nd->nd_flag & ND_NFSV41) != 0)
2741 clientid.qval = nd->nd_clientid.qval;
2742 else if (nd->nd_clientid.qval != clientid.qval)
2743 printf("EEK6 multiple clids\n");
2745 if ((nd->nd_flag & ND_NFSV41) != 0)
2746 printf("EEK! no clientid from session\n");
2747 nd->nd_flag |= ND_IMPLIEDCLID;
2748 nd->nd_clientid.qval = clientid.qval;
2750 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2751 if (vnode_vtype(vp) == VDIR)
2752 nd->nd_repstat = NFSERR_ISDIR;
2754 nd->nd_repstat = NFSERR_INVAL;
2757 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2758 * seqid# gets incremented. nfsrv_lockctrl() will return the
2759 * value of nd_repstat, if it gets that far.
2761 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2762 &stateid, exp, nd, p);
2764 free(stp, M_NFSDSTATE);
2766 free(lop, M_NFSDLOCK);
2767 if (!nd->nd_repstat) {
2768 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2769 *tl++ = txdr_unsigned(stateid.seqid);
2770 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2774 NFSEXITCODE2(error, nd);
2779 * nfsv4 open service
2782 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2783 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, struct nfsexstuff *exp)
2787 struct nfsstate *stp = NULL;
2788 int error = 0, create, claim, exclusive_flag = 0, override;
2789 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2790 int how = NFSCREATE_UNCHECKED;
2791 int32_t cverf[2], tverf[2] = { 0, 0 };
2792 vnode_t vp = NULL, dirp = NULL;
2793 struct nfsvattr nva, dirfor, diraft;
2794 struct nameidata named;
2795 nfsv4stateid_t stateid, delegstateid;
2796 nfsattrbit_t attrbits;
2800 NFSACL_T *aclp = NULL;
2801 struct thread *p = curthread;
2803 #ifdef NFS4_ACL_EXTATTR_NAME
2804 aclp = acl_alloc(M_WAITOK);
2807 NFSZERO_ATTRBIT(&attrbits);
2808 named.ni_startdir = NULL;
2809 named.ni_cnd.cn_nameiop = 0;
2810 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2811 i = fxdr_unsigned(int, *(tl + 5));
2812 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2813 nd->nd_repstat = NFSERR_BADXDR;
2816 stp = malloc(sizeof (struct nfsstate) + i,
2817 M_NFSDSTATE, M_WAITOK);
2818 stp->ls_ownerlen = i;
2819 stp->ls_op = nd->nd_rp;
2820 stp->ls_flags = NFSLCK_OPEN;
2821 stp->ls_uid = nd->nd_cred->cr_uid;
2822 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2823 i = fxdr_unsigned(int, *tl++);
2825 if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG |
2826 NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) {
2828 /* For now, ignore these. */
2829 i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG);
2830 switch (i & NFSV4OPEN_WANTDELEGMASK) {
2831 case NFSV4OPEN_WANTANYDELEG:
2832 stp->ls_flags |= (NFSLCK_WANTRDELEG |
2834 i &= ~NFSV4OPEN_WANTDELEGMASK;
2836 case NFSV4OPEN_WANTREADDELEG:
2837 stp->ls_flags |= NFSLCK_WANTRDELEG;
2838 i &= ~NFSV4OPEN_WANTDELEGMASK;
2840 case NFSV4OPEN_WANTWRITEDELEG:
2841 stp->ls_flags |= NFSLCK_WANTWDELEG;
2842 i &= ~NFSV4OPEN_WANTDELEGMASK;
2844 case NFSV4OPEN_WANTNODELEG:
2845 stp->ls_flags |= NFSLCK_WANTNODELEG;
2846 i &= ~NFSV4OPEN_WANTDELEGMASK;
2848 case NFSV4OPEN_WANTCANCEL:
2849 printf("NFSv4: ignore Open WantCancel\n");
2850 i &= ~NFSV4OPEN_WANTDELEGMASK;
2853 /* nd_repstat will be set to NFSERR_INVAL below. */
2858 case NFSV4OPEN_ACCESSREAD:
2859 stp->ls_flags |= NFSLCK_READACCESS;
2861 case NFSV4OPEN_ACCESSWRITE:
2862 stp->ls_flags |= NFSLCK_WRITEACCESS;
2864 case NFSV4OPEN_ACCESSBOTH:
2865 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2868 nd->nd_repstat = NFSERR_INVAL;
2870 i = fxdr_unsigned(int, *tl++);
2872 case NFSV4OPEN_DENYNONE:
2874 case NFSV4OPEN_DENYREAD:
2875 stp->ls_flags |= NFSLCK_READDENY;
2877 case NFSV4OPEN_DENYWRITE:
2878 stp->ls_flags |= NFSLCK_WRITEDENY;
2880 case NFSV4OPEN_DENYBOTH:
2881 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
2884 nd->nd_repstat = NFSERR_INVAL;
2886 clientid.lval[0] = *tl++;
2887 clientid.lval[1] = *tl;
2888 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2889 if ((nd->nd_flag & ND_NFSV41) != 0)
2890 clientid.qval = nd->nd_clientid.qval;
2891 else if (nd->nd_clientid.qval != clientid.qval)
2892 printf("EEK7 multiple clids\n");
2894 if ((nd->nd_flag & ND_NFSV41) != 0)
2895 printf("EEK! no clientid from session\n");
2896 nd->nd_flag |= ND_IMPLIEDCLID;
2897 nd->nd_clientid.qval = clientid.qval;
2899 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2902 NFSVNO_ATTRINIT(&nva);
2903 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2904 create = fxdr_unsigned(int, *tl);
2905 if (!nd->nd_repstat)
2906 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
2907 if (create == NFSV4OPEN_CREATE) {
2910 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2911 how = fxdr_unsigned(int, *tl);
2913 case NFSCREATE_UNCHECKED:
2914 case NFSCREATE_GUARDED:
2915 error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
2919 * If the na_gid being set is the same as that of
2920 * the directory it is going in, clear it, since
2921 * that is what will be set by default. This allows
2922 * a user that isn't in that group to do the create.
2924 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
2925 nva.na_gid == dirfor.na_gid)
2926 NFSVNO_UNSET(&nva, gid);
2927 if (!nd->nd_repstat)
2928 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2930 case NFSCREATE_EXCLUSIVE:
2931 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2935 case NFSCREATE_EXCLUSIVE41:
2936 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2939 error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
2942 if (NFSISSET_ATTRBIT(&attrbits,
2943 NFSATTRBIT_TIMEACCESSSET))
2944 nd->nd_repstat = NFSERR_INVAL;
2946 * If the na_gid being set is the same as that of
2947 * the directory it is going in, clear it, since
2948 * that is what will be set by default. This allows
2949 * a user that isn't in that group to do the create.
2951 if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) &&
2952 nva.na_gid == dirfor.na_gid)
2953 NFSVNO_UNSET(&nva, gid);
2954 if (nd->nd_repstat == 0)
2955 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2958 nd->nd_repstat = NFSERR_BADXDR;
2961 } else if (create != NFSV4OPEN_NOCREATE) {
2962 nd->nd_repstat = NFSERR_BADXDR;
2967 * Now, handle the claim, which usually includes looking up a
2968 * name in the directory referenced by dp. The exception is
2969 * NFSV4OPEN_CLAIMPREVIOUS.
2971 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2972 claim = fxdr_unsigned(int, *tl);
2973 if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
2974 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2975 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2976 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
2977 stp->ls_flags |= NFSLCK_DELEGCUR;
2978 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2979 stp->ls_flags |= NFSLCK_DELEGPREV;
2981 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
2982 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2983 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
2984 claim != NFSV4OPEN_CLAIMNULL)
2985 nd->nd_repstat = NFSERR_INVAL;
2986 if (nd->nd_repstat) {
2987 nd->nd_repstat = nfsrv_opencheck(clientid,
2988 &stateid, stp, NULL, nd, p, nd->nd_repstat);
2991 if (create == NFSV4OPEN_CREATE)
2992 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
2993 LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
2995 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
2996 LOCKLEAF | SAVESTART);
2997 nfsvno_setpathbuf(&named, &bufp, &hashp);
2998 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3001 #ifdef NFS4_ACL_EXTATTR_NAME
3004 free(stp, M_NFSDSTATE);
3005 nfsvno_relpathbuf(&named);
3006 NFSEXITCODE2(error, nd);
3009 if (!nd->nd_repstat) {
3010 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
3014 nfsvno_relpathbuf(&named);
3016 if (create == NFSV4OPEN_CREATE) {
3018 case NFSCREATE_UNCHECKED:
3021 * Clear the setable attribute bits, except
3022 * for Size, if it is being truncated.
3024 NFSZERO_ATTRBIT(&attrbits);
3025 if (NFSVNO_ISSETSIZE(&nva))
3026 NFSSETBIT_ATTRBIT(&attrbits,
3030 case NFSCREATE_GUARDED:
3031 if (named.ni_vp && !nd->nd_repstat)
3032 nd->nd_repstat = EEXIST;
3034 case NFSCREATE_EXCLUSIVE:
3039 case NFSCREATE_EXCLUSIVE41:
3044 nfsvno_open(nd, &named, clientid, &stateid, stp,
3045 &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
3046 nd->nd_cred, exp, &vp);
3047 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim ==
3048 NFSV4OPEN_CLAIMFH) {
3049 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
3050 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3051 i = fxdr_unsigned(int, *tl);
3053 case NFSV4OPEN_DELEGATEREAD:
3054 stp->ls_flags |= NFSLCK_DELEGREAD;
3056 case NFSV4OPEN_DELEGATEWRITE:
3057 stp->ls_flags |= NFSLCK_DELEGWRITE;
3058 case NFSV4OPEN_DELEGATENONE:
3061 nd->nd_repstat = NFSERR_BADXDR;
3064 stp->ls_flags |= NFSLCK_RECLAIM;
3067 if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE)
3068 nd->nd_repstat = NFSERR_INVAL;
3071 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
3072 if (!VN_IS_DOOMED(vp))
3073 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
3074 stp, vp, nd, p, nd->nd_repstat);
3076 nd->nd_repstat = NFSERR_PERM;
3078 nd->nd_repstat = NFSERR_BADXDR;
3083 * Do basic access checking.
3085 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
3087 * The IETF working group decided that this is the correct
3088 * error return for all non-regular files.
3090 nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK;
3094 * If the Open is being done for a file that already exists, apply
3095 * normal permission checking including for the file owner, if
3096 * vfs.nfsd.v4openaccess is set.
3097 * Previously, the owner was always allowed to open the file to
3098 * be consistent with the NFS tradition of always allowing the
3099 * owner of the file to write to the file regardless of permissions.
3100 * It now appears that the Linux client expects the owner
3101 * permissions to be checked for opens that are not creating the
3102 * file. I believe the correct approach is to use the Access
3103 * operation's results to be consistent with NFSv3, but that is
3104 * not what the current Linux client appears to be doing.
3105 * Since both the Linux and OpenSolaris NFSv4 servers do this check,
3106 * I have enabled it by default.
3107 * If this semantic change causes a problem, it can be disabled by
3108 * setting the sysctl vfs.nfsd.v4openaccess to 0 to re-enable the
3109 * previous semantics.
3111 if (nfsrv_openaccess && create == NFSV4OPEN_NOCREATE)
3112 override = NFSACCCHK_NOOVERRIDE;
3114 override = NFSACCCHK_ALLOWOWNER;
3115 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
3116 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
3117 exp, p, override, NFSACCCHK_VPISLOCKED, NULL);
3118 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
3119 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
3120 exp, p, override, NFSACCCHK_VPISLOCKED, NULL);
3122 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
3123 nd->nd_cred, exp, p, override,
3124 NFSACCCHK_VPISLOCKED, NULL);
3127 if (!nd->nd_repstat) {
3128 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
3129 if (!nd->nd_repstat) {
3130 tverf[0] = nva.na_atime.tv_sec;
3131 tverf[1] = nva.na_atime.tv_nsec;
3134 if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
3135 cverf[1] != tverf[1]))
3136 nd->nd_repstat = EEXIST;
3138 * Do the open locking/delegation stuff.
3140 if (!nd->nd_repstat)
3141 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
3142 &delegstateid, &rflags, exp, p, nva.na_filerev);
3145 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
3146 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
3147 * (ie: Leave the NFSVOPUNLOCK() about here.)
3152 free(stp, M_NFSDSTATE);
3153 if (!nd->nd_repstat && dirp)
3154 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
3155 if (!nd->nd_repstat) {
3156 /* For NFSv4.1, set the Current StateID. */
3157 if ((nd->nd_flag & ND_NFSV41) != 0) {
3158 nd->nd_curstateid = stateid;
3159 nd->nd_flag |= ND_CURSTATEID;
3161 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
3162 *tl++ = txdr_unsigned(stateid.seqid);
3163 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3164 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3165 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
3166 *tl++ = newnfs_true;
3172 *tl++ = newnfs_false; /* Since dirp is not locked */
3173 txdr_hyper(dirfor.na_filerev, tl);
3175 txdr_hyper(diraft.na_filerev, tl);
3178 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
3179 (void) nfsrv_putattrbit(nd, &attrbits);
3180 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3181 if (rflags & NFSV4OPEN_READDELEGATE)
3182 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
3183 else if (rflags & NFSV4OPEN_WRITEDELEGATE)
3184 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
3185 else if (retext != 0) {
3186 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT);
3187 if ((rflags & NFSV4OPEN_WDNOTWANTED) != 0) {
3188 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3189 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
3190 } else if ((rflags & NFSV4OPEN_WDSUPPFTYPE) != 0) {
3191 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3192 *tl = txdr_unsigned(NFSV4OPEN_NOTSUPPFTYPE);
3193 } else if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) {
3194 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3195 *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION);
3197 } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) {
3198 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3199 *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE);
3202 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3203 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
3206 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
3207 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
3208 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
3209 *tl++ = txdr_unsigned(delegstateid.seqid);
3210 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
3212 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3213 if (rflags & NFSV4OPEN_RECALL)
3217 if (rflags & NFSV4OPEN_WRITEDELEGATE) {
3218 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3219 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
3220 txdr_hyper(nva.na_size, tl);
3222 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3223 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
3224 *tl++ = txdr_unsigned(0x0);
3225 acemask = NFSV4ACE_ALLFILESMASK;
3226 if (nva.na_mode & S_IRUSR)
3227 acemask |= NFSV4ACE_READMASK;
3228 if (nva.na_mode & S_IWUSR)
3229 acemask |= NFSV4ACE_WRITEMASK;
3230 if (nva.na_mode & S_IXUSR)
3231 acemask |= NFSV4ACE_EXECUTEMASK;
3232 *tl = txdr_unsigned(acemask);
3233 (void) nfsm_strtom(nd, "OWNER@", 6);
3241 #ifdef NFS4_ACL_EXTATTR_NAME
3244 NFSEXITCODE2(0, nd);
3248 #ifdef NFS4_ACL_EXTATTR_NAME
3252 free(stp, M_NFSDSTATE);
3253 NFSEXITCODE2(error, nd);
3258 * nfsv4 close service
3261 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
3262 vnode_t vp, __unused struct nfsexstuff *exp)
3265 struct nfsstate st, *stp = &st;
3266 int error = 0, writeacc;
3267 nfsv4stateid_t stateid;
3270 struct thread *p = curthread;
3272 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
3273 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3274 stp->ls_ownerlen = 0;
3275 stp->ls_op = nd->nd_rp;
3276 stp->ls_uid = nd->nd_cred->cr_uid;
3277 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3278 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3282 * For the special stateid of other all 0s and seqid == 1, set the
3283 * stateid to the current stateid, if it is set.
3285 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
3286 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
3287 stp->ls_stateid.other[2] == 0) {
3288 if ((nd->nd_flag & ND_CURSTATEID) != 0)
3289 stp->ls_stateid = nd->nd_curstateid;
3291 nd->nd_repstat = NFSERR_BADSTATEID;
3296 stp->ls_flags = NFSLCK_CLOSE;
3297 clientid.lval[0] = stp->ls_stateid.other[0];
3298 clientid.lval[1] = stp->ls_stateid.other[1];
3299 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3300 if ((nd->nd_flag & ND_NFSV41) != 0)
3301 clientid.qval = nd->nd_clientid.qval;
3302 else if (nd->nd_clientid.qval != clientid.qval)
3303 printf("EEK8 multiple clids\n");
3305 if ((nd->nd_flag & ND_NFSV41) != 0)
3306 printf("EEK! no clientid from session\n");
3307 nd->nd_flag |= ND_IMPLIEDCLID;
3308 nd->nd_clientid.qval = clientid.qval;
3310 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
3312 /* For pNFS, update the attributes. */
3313 if (writeacc != 0 || nfsrv_pnfsatime != 0)
3314 nfsrv_updatemdsattr(vp, &na, p);
3316 if (!nd->nd_repstat) {
3318 * If the stateid that has been closed is the current stateid,
3321 if ((nd->nd_flag & ND_CURSTATEID) != 0 &&
3322 stateid.other[0] == nd->nd_curstateid.other[0] &&
3323 stateid.other[1] == nd->nd_curstateid.other[1] &&
3324 stateid.other[2] == nd->nd_curstateid.other[2])
3325 nd->nd_flag &= ~ND_CURSTATEID;
3326 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3327 *tl++ = txdr_unsigned(stateid.seqid);
3328 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3330 NFSEXITCODE2(0, nd);
3334 NFSEXITCODE2(error, nd);
3339 * nfsv4 delegpurge service
3342 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
3343 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3348 struct thread *p = curthread;
3350 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3351 nd->nd_repstat = NFSERR_WRONGSEC;
3354 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3355 clientid.lval[0] = *tl++;
3356 clientid.lval[1] = *tl;
3357 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3358 if ((nd->nd_flag & ND_NFSV41) != 0)
3359 clientid.qval = nd->nd_clientid.qval;
3360 else if (nd->nd_clientid.qval != clientid.qval)
3361 printf("EEK9 multiple clids\n");
3363 if ((nd->nd_flag & ND_NFSV41) != 0)
3364 printf("EEK! no clientid from session\n");
3365 nd->nd_flag |= ND_IMPLIEDCLID;
3366 nd->nd_clientid.qval = clientid.qval;
3368 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL,
3369 NFSV4OP_DELEGPURGE, nd->nd_cred, p, NULL);
3371 NFSEXITCODE2(error, nd);
3376 * nfsv4 delegreturn service
3379 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
3380 vnode_t vp, __unused struct nfsexstuff *exp)
3383 int error = 0, writeacc;
3384 nfsv4stateid_t stateid;
3387 struct thread *p = curthread;
3389 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3390 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3391 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
3392 clientid.lval[0] = stateid.other[0];
3393 clientid.lval[1] = stateid.other[1];
3394 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3395 if ((nd->nd_flag & ND_NFSV41) != 0)
3396 clientid.qval = nd->nd_clientid.qval;
3397 else if (nd->nd_clientid.qval != clientid.qval)
3398 printf("EEK10 multiple clids\n");
3400 if ((nd->nd_flag & ND_NFSV41) != 0)
3401 printf("EEK! no clientid from session\n");
3402 nd->nd_flag |= ND_IMPLIEDCLID;
3403 nd->nd_clientid.qval = clientid.qval;
3405 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp,
3406 NFSV4OP_DELEGRETURN, nd->nd_cred, p, &writeacc);
3407 /* For pNFS, update the attributes. */
3408 if (writeacc != 0 || nfsrv_pnfsatime != 0)
3409 nfsrv_updatemdsattr(vp, &na, p);
3412 NFSEXITCODE2(error, nd);
3417 * nfsv4 get file handle service
3420 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
3421 vnode_t vp, __unused struct nfsexstuff *exp)
3424 struct thread *p = curthread;
3426 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3428 if (!nd->nd_repstat)
3429 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
3430 NFSEXITCODE2(0, nd);
3435 * nfsv4 open confirm service
3438 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
3439 vnode_t vp, __unused struct nfsexstuff *exp)
3442 struct nfsstate st, *stp = &st;
3444 nfsv4stateid_t stateid;
3446 struct thread *p = curthread;
3448 if ((nd->nd_flag & ND_NFSV41) != 0) {
3449 nd->nd_repstat = NFSERR_NOTSUPP;
3452 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
3453 stp->ls_ownerlen = 0;
3454 stp->ls_op = nd->nd_rp;
3455 stp->ls_uid = nd->nd_cred->cr_uid;
3456 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3457 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3459 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3460 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
3461 stp->ls_flags = NFSLCK_CONFIRM;
3462 clientid.lval[0] = stp->ls_stateid.other[0];
3463 clientid.lval[1] = stp->ls_stateid.other[1];
3464 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3465 if ((nd->nd_flag & ND_NFSV41) != 0)
3466 clientid.qval = nd->nd_clientid.qval;
3467 else if (nd->nd_clientid.qval != clientid.qval)
3468 printf("EEK11 multiple clids\n");
3470 if ((nd->nd_flag & ND_NFSV41) != 0)
3471 printf("EEK! no clientid from session\n");
3472 nd->nd_flag |= ND_IMPLIEDCLID;
3473 nd->nd_clientid.qval = clientid.qval;
3475 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
3477 if (!nd->nd_repstat) {
3478 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3479 *tl++ = txdr_unsigned(stateid.seqid);
3480 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3484 NFSEXITCODE2(error, nd);
3489 * nfsv4 open downgrade service
3492 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
3493 vnode_t vp, __unused struct nfsexstuff *exp)
3497 struct nfsstate st, *stp = &st;
3499 nfsv4stateid_t stateid;
3501 struct thread *p = curthread;
3503 /* opendowngrade can only work on a file object.*/
3504 if (vp->v_type != VREG) {
3505 error = NFSERR_INVAL;
3508 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
3509 stp->ls_ownerlen = 0;
3510 stp->ls_op = nd->nd_rp;
3511 stp->ls_uid = nd->nd_cred->cr_uid;
3512 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3513 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3515 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3518 * For the special stateid of other all 0s and seqid == 1, set the
3519 * stateid to the current stateid, if it is set.
3521 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
3522 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
3523 stp->ls_stateid.other[2] == 0) {
3524 if ((nd->nd_flag & ND_CURSTATEID) != 0)
3525 stp->ls_stateid = nd->nd_curstateid;
3527 nd->nd_repstat = NFSERR_BADSTATEID;
3532 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3533 i = fxdr_unsigned(int, *tl++);
3534 if ((nd->nd_flag & ND_NFSV41) != 0)
3535 i &= ~NFSV4OPEN_WANTDELEGMASK;
3537 case NFSV4OPEN_ACCESSREAD:
3538 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
3540 case NFSV4OPEN_ACCESSWRITE:
3541 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
3543 case NFSV4OPEN_ACCESSBOTH:
3544 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
3548 nd->nd_repstat = NFSERR_INVAL;
3550 i = fxdr_unsigned(int, *tl);
3552 case NFSV4OPEN_DENYNONE:
3554 case NFSV4OPEN_DENYREAD:
3555 stp->ls_flags |= NFSLCK_READDENY;
3557 case NFSV4OPEN_DENYWRITE:
3558 stp->ls_flags |= NFSLCK_WRITEDENY;
3560 case NFSV4OPEN_DENYBOTH:
3561 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3564 nd->nd_repstat = NFSERR_INVAL;
3567 clientid.lval[0] = stp->ls_stateid.other[0];
3568 clientid.lval[1] = stp->ls_stateid.other[1];
3569 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3570 if ((nd->nd_flag & ND_NFSV41) != 0)
3571 clientid.qval = nd->nd_clientid.qval;
3572 else if (nd->nd_clientid.qval != clientid.qval)
3573 printf("EEK12 multiple clids\n");
3575 if ((nd->nd_flag & ND_NFSV41) != 0)
3576 printf("EEK! no clientid from session\n");
3577 nd->nd_flag |= ND_IMPLIEDCLID;
3578 nd->nd_clientid.qval = clientid.qval;
3580 if (!nd->nd_repstat)
3581 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3583 if (!nd->nd_repstat) {
3584 /* For NFSv4.1, set the Current StateID. */
3585 if ((nd->nd_flag & ND_NFSV41) != 0) {
3586 nd->nd_curstateid = stateid;
3587 nd->nd_flag |= ND_CURSTATEID;
3589 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3590 *tl++ = txdr_unsigned(stateid.seqid);
3591 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3595 NFSEXITCODE2(error, nd);
3600 * nfsv4 renew lease service
3603 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3604 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3609 struct thread *p = curthread;
3611 if ((nd->nd_flag & ND_NFSV41) != 0) {
3612 nd->nd_repstat = NFSERR_NOTSUPP;
3615 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3616 nd->nd_repstat = NFSERR_WRONGSEC;
3619 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3620 clientid.lval[0] = *tl++;
3621 clientid.lval[1] = *tl;
3622 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3623 if ((nd->nd_flag & ND_NFSV41) != 0)
3624 clientid.qval = nd->nd_clientid.qval;
3625 else if (nd->nd_clientid.qval != clientid.qval)
3626 printf("EEK13 multiple clids\n");
3628 if ((nd->nd_flag & ND_NFSV41) != 0)
3629 printf("EEK! no clientid from session\n");
3630 nd->nd_flag |= ND_IMPLIEDCLID;
3631 nd->nd_clientid.qval = clientid.qval;
3633 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3634 NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p);
3636 NFSEXITCODE2(error, nd);
3641 * nfsv4 security info service
3644 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3645 vnode_t dp, struct nfsexstuff *exp)
3649 struct nameidata named;
3650 vnode_t dirp = NULL, vp;
3652 struct nfsexstuff retnes;
3654 int error = 0, savflag, i;
3657 struct thread *p = curthread;
3660 * All this just to get the export flags for the name.
3662 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3663 LOCKLEAF | SAVESTART);
3664 nfsvno_setpathbuf(&named, &bufp, &hashp);
3665 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3668 nfsvno_relpathbuf(&named);
3671 if (!nd->nd_repstat) {
3672 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
3675 nfsvno_relpathbuf(&named);
3681 vrele(named.ni_startdir);
3682 nfsvno_relpathbuf(&named);
3683 fh.nfsrvfh_len = NFSX_MYFH;
3685 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3687 savflag = nd->nd_flag;
3688 if (!nd->nd_repstat) {
3689 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0);
3693 nd->nd_flag = savflag;
3698 * Finally have the export flags for name, so we can create
3699 * the security info.
3702 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3703 for (i = 0; i < retnes.nes_numsecflavor; i++) {
3704 if (retnes.nes_secflavors[i] == AUTH_SYS) {
3705 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3706 *tl = txdr_unsigned(RPCAUTH_UNIX);
3708 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3709 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3710 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3711 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3712 nfsgss_mechlist[KERBV_MECH].len);
3713 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3714 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3715 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3717 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3718 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3719 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3720 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3721 nfsgss_mechlist[KERBV_MECH].len);
3722 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3723 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3724 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3726 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3727 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3728 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3729 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3730 nfsgss_mechlist[KERBV_MECH].len);
3731 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3732 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3733 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3737 *sizp = txdr_unsigned(len);
3740 NFSEXITCODE2(error, nd);
3745 * nfsv4 set client id service
3748 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3749 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3753 int error = 0, idlen;
3754 struct nfsclient *clp = NULL;
3756 struct sockaddr_in *rin;
3759 struct sockaddr_in6 *rin6;
3761 #if defined(INET) || defined(INET6)
3764 u_char *verf, *addrbuf;
3765 nfsquad_t clientid, confirm;
3766 struct thread *p = curthread;
3768 if ((nd->nd_flag & ND_NFSV41) != 0) {
3769 nd->nd_repstat = NFSERR_NOTSUPP;
3772 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3773 nd->nd_repstat = NFSERR_WRONGSEC;
3776 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3777 verf = (u_char *)tl;
3778 tl += (NFSX_VERF / NFSX_UNSIGNED);
3779 i = fxdr_unsigned(int, *tl);
3780 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3781 nd->nd_repstat = NFSERR_BADXDR;
3785 if (nd->nd_flag & ND_GSS)
3786 i += nd->nd_princlen;
3787 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
3789 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
3790 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
3791 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3792 /* Allocated large enough for an AF_INET or AF_INET6 socket. */
3793 clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
3795 clp->lc_req.nr_cred = NULL;
3796 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3797 clp->lc_idlen = idlen;
3798 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3801 if (nd->nd_flag & ND_GSS) {
3802 clp->lc_flags = LCL_GSS;
3803 if (nd->nd_flag & ND_GSSINTEGRITY)
3804 clp->lc_flags |= LCL_GSSINTEGRITY;
3805 else if (nd->nd_flag & ND_GSSPRIVACY)
3806 clp->lc_flags |= LCL_GSSPRIVACY;
3810 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
3811 clp->lc_flags |= LCL_NAME;
3812 clp->lc_namelen = nd->nd_princlen;
3813 clp->lc_name = &clp->lc_id[idlen];
3814 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3816 clp->lc_uid = nd->nd_cred->cr_uid;
3817 clp->lc_gid = nd->nd_cred->cr_gid;
3820 /* If the client is using TLS, do so for the callback connection. */
3821 if (nd->nd_flag & ND_TLS)
3822 clp->lc_flags |= LCL_TLSCB;
3824 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3825 clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
3826 error = nfsrv_getclientipaddr(nd, clp);
3829 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3830 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
3833 * nfsrv_setclient() does the actual work of adding it to the
3834 * client list. If there is no error, the structure has been
3835 * linked into the client list and clp should no longer be used
3836 * here. When an error is returned, it has not been linked in,
3837 * so it should be free'd.
3839 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3840 if (nd->nd_repstat == NFSERR_CLIDINUSE) {
3842 * 8 is the maximum length of the port# string.
3844 addrbuf = malloc(INET6_ADDRSTRLEN + 8, M_TEMP, M_WAITOK);
3845 switch (clp->lc_req.nr_nam->sa_family) {
3848 if (clp->lc_flags & LCL_TCPCALLBACK)
3849 (void) nfsm_strtom(nd, "tcp", 3);
3851 (void) nfsm_strtom(nd, "udp", 3);
3852 rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
3853 ucp = (u_char *)&rin->sin_addr.s_addr;
3854 ucp2 = (u_char *)&rin->sin_port;
3855 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
3856 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
3857 ucp2[0] & 0xff, ucp2[1] & 0xff);
3862 if (clp->lc_flags & LCL_TCPCALLBACK)
3863 (void) nfsm_strtom(nd, "tcp6", 4);
3865 (void) nfsm_strtom(nd, "udp6", 4);
3866 rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
3867 ucp = inet_ntop(AF_INET6, &rin6->sin6_addr, addrbuf,
3873 ucp2 = (u_char *)&rin6->sin6_port;
3874 sprintf(&addrbuf[i], ".%d.%d", ucp2[0] & 0xff,
3879 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
3880 free(addrbuf, M_TEMP);
3883 free(clp->lc_req.nr_nam, M_SONAME);
3884 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3885 free(clp->lc_stateid, M_NFSDCLIENT);
3886 free(clp, M_NFSDCLIENT);
3888 if (!nd->nd_repstat) {
3889 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
3890 *tl++ = clientid.lval[0];
3891 *tl++ = clientid.lval[1];
3892 *tl++ = confirm.lval[0];
3893 *tl = confirm.lval[1];
3897 NFSEXITCODE2(0, nd);
3901 free(clp->lc_req.nr_nam, M_SONAME);
3902 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3903 free(clp->lc_stateid, M_NFSDCLIENT);
3904 free(clp, M_NFSDCLIENT);
3906 NFSEXITCODE2(error, nd);
3911 * nfsv4 set client id confirm service
3914 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
3915 __unused int isdgram, __unused vnode_t vp,
3916 __unused struct nfsexstuff *exp)
3920 nfsquad_t clientid, confirm;
3921 struct thread *p = curthread;
3923 if ((nd->nd_flag & ND_NFSV41) != 0) {
3924 nd->nd_repstat = NFSERR_NOTSUPP;
3927 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3928 nd->nd_repstat = NFSERR_WRONGSEC;
3931 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
3932 clientid.lval[0] = *tl++;
3933 clientid.lval[1] = *tl++;
3934 confirm.lval[0] = *tl++;
3935 confirm.lval[1] = *tl;
3938 * nfsrv_getclient() searches the client list for a match and
3939 * returns the appropriate NFSERR status.
3941 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
3942 NULL, NULL, confirm, 0, nd, p);
3944 NFSEXITCODE2(error, nd);
3949 * nfsv4 verify service
3952 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
3953 vnode_t vp, __unused struct nfsexstuff *exp)
3955 int error = 0, ret, fhsize = NFSX_MYFH;
3956 struct nfsvattr nva;
3958 struct nfsfsinfo fs;
3960 struct thread *p = curthread;
3962 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
3963 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
3964 if (!nd->nd_repstat)
3965 nd->nd_repstat = nfsvno_statfs(vp, sf);
3966 if (!nd->nd_repstat)
3967 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3968 if (!nd->nd_repstat) {
3969 nfsvno_getfs(&fs, isdgram);
3970 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
3971 sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
3973 if (nd->nd_procnum == NFSV4OP_NVERIFY) {
3975 nd->nd_repstat = NFSERR_SAME;
3976 else if (ret != NFSERR_NOTSAME)
3977 nd->nd_repstat = ret;
3979 nd->nd_repstat = ret;
3984 NFSEXITCODE2(error, nd);
3992 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
3993 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
3994 __unused struct nfsexstuff *exp)
3997 int error = 0, createdir __unused;
3999 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4000 createdir = fxdr_unsigned(int, *tl);
4001 nd->nd_repstat = NFSERR_NOTSUPP;
4004 NFSEXITCODE2(error, nd);
4009 * nfsv4 release lock owner service
4012 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
4013 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4016 struct nfsstate *stp = NULL;
4019 struct thread *p = curthread;
4021 if ((nd->nd_flag & ND_NFSV41) != 0) {
4022 nd->nd_repstat = NFSERR_NOTSUPP;
4025 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4026 nd->nd_repstat = NFSERR_WRONGSEC;
4029 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
4030 len = fxdr_unsigned(int, *(tl + 2));
4031 if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
4032 nd->nd_repstat = NFSERR_BADXDR;
4035 stp = malloc(sizeof (struct nfsstate) + len,
4036 M_NFSDSTATE, M_WAITOK);
4037 stp->ls_ownerlen = len;
4039 stp->ls_flags = NFSLCK_RELEASE;
4040 stp->ls_uid = nd->nd_cred->cr_uid;
4041 clientid.lval[0] = *tl++;
4042 clientid.lval[1] = *tl;
4043 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
4044 if ((nd->nd_flag & ND_NFSV41) != 0)
4045 clientid.qval = nd->nd_clientid.qval;
4046 else if (nd->nd_clientid.qval != clientid.qval)
4047 printf("EEK14 multiple clids\n");
4049 if ((nd->nd_flag & ND_NFSV41) != 0)
4050 printf("EEK! no clientid from session\n");
4051 nd->nd_flag |= ND_IMPLIEDCLID;
4052 nd->nd_clientid.qval = clientid.qval;
4054 error = nfsrv_mtostr(nd, stp->ls_owner, len);
4057 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
4058 free(stp, M_NFSDSTATE);
4060 NFSEXITCODE2(0, nd);
4064 free(stp, M_NFSDSTATE);
4065 NFSEXITCODE2(error, nd);
4070 * nfsv4 exchange_id service
4073 nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram,
4074 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4077 int error = 0, i, idlen;
4078 struct nfsclient *clp = NULL;
4079 nfsquad_t clientid, confirm;
4081 uint32_t sp4type, v41flags;
4082 uint64_t owner_minor;
4083 struct timespec verstime;
4085 struct sockaddr_in *sin, *rin;
4088 struct sockaddr_in6 *sin6, *rin6;
4090 struct thread *p = curthread;
4092 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4093 nd->nd_repstat = NFSERR_WRONGSEC;
4096 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
4097 verf = (uint8_t *)tl;
4098 tl += (NFSX_VERF / NFSX_UNSIGNED);
4099 i = fxdr_unsigned(int, *tl);
4100 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
4101 nd->nd_repstat = NFSERR_BADXDR;
4105 if (nd->nd_flag & ND_GSS)
4106 i += nd->nd_princlen;
4107 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
4109 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
4110 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
4111 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
4112 /* Allocated large enough for an AF_INET or AF_INET6 socket. */
4113 clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
4115 switch (nd->nd_nam->sa_family) {
4118 rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
4119 sin = (struct sockaddr_in *)nd->nd_nam;
4120 rin->sin_family = AF_INET;
4121 rin->sin_len = sizeof(struct sockaddr_in);
4123 rin->sin_addr.s_addr = sin->sin_addr.s_addr;
4128 rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
4129 sin6 = (struct sockaddr_in6 *)nd->nd_nam;
4130 rin6->sin6_family = AF_INET6;
4131 rin6->sin6_len = sizeof(struct sockaddr_in6);
4132 rin6->sin6_port = 0;
4133 rin6->sin6_addr = sin6->sin6_addr;
4137 clp->lc_req.nr_cred = NULL;
4138 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
4139 clp->lc_idlen = idlen;
4140 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
4143 if ((nd->nd_flag & ND_GSS) != 0) {
4144 clp->lc_flags = LCL_GSS | LCL_NFSV41;
4145 if ((nd->nd_flag & ND_GSSINTEGRITY) != 0)
4146 clp->lc_flags |= LCL_GSSINTEGRITY;
4147 else if ((nd->nd_flag & ND_GSSPRIVACY) != 0)
4148 clp->lc_flags |= LCL_GSSPRIVACY;
4150 clp->lc_flags = LCL_NFSV41;
4151 if ((nd->nd_flag & ND_NFSV42) != 0)
4152 clp->lc_flags |= LCL_NFSV42;
4153 if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) {
4154 clp->lc_flags |= LCL_NAME;
4155 clp->lc_namelen = nd->nd_princlen;
4156 clp->lc_name = &clp->lc_id[idlen];
4157 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
4159 clp->lc_uid = nd->nd_cred->cr_uid;
4160 clp->lc_gid = nd->nd_cred->cr_gid;
4162 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4163 v41flags = fxdr_unsigned(uint32_t, *tl++);
4164 if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR |
4165 NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS |
4166 NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) {
4167 nd->nd_repstat = NFSERR_INVAL;
4170 if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0)
4171 confirm.lval[1] = 1;
4173 confirm.lval[1] = 0;
4174 if (nfsrv_devidcnt == 0)
4175 v41flags = NFSV4EXCH_USENONPNFS | NFSV4EXCH_USEPNFSDS;
4177 v41flags = NFSV4EXCH_USEPNFSMDS;
4178 sp4type = fxdr_unsigned(uint32_t, *tl);
4179 if (sp4type != NFSV4EXCH_SP4NONE) {
4180 nd->nd_repstat = NFSERR_NOTSUPP;
4185 * nfsrv_setclient() does the actual work of adding it to the
4186 * client list. If there is no error, the structure has been
4187 * linked into the client list and clp should no longer be used
4188 * here. When an error is returned, it has not been linked in,
4189 * so it should be free'd.
4191 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
4193 free(clp->lc_req.nr_nam, M_SONAME);
4194 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4195 free(clp->lc_stateid, M_NFSDCLIENT);
4196 free(clp, M_NFSDCLIENT);
4198 if (nd->nd_repstat == 0) {
4199 if (confirm.lval[1] != 0)
4200 v41flags |= NFSV4EXCH_CONFIRMEDR;
4201 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED);
4202 *tl++ = clientid.lval[0]; /* ClientID */
4203 *tl++ = clientid.lval[1];
4204 *tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */
4205 *tl++ = txdr_unsigned(v41flags); /* Exch flags */
4206 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); /* No SSV */
4207 owner_minor = 0; /* Owner */
4208 txdr_hyper(owner_minor, tl); /* Minor */
4209 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid,
4210 strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */
4211 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid,
4212 strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Scope */
4213 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4214 *tl = txdr_unsigned(1);
4215 (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
4216 (void)nfsm_strtom(nd, version, strlen(version));
4217 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
4218 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */
4219 verstime.tv_nsec = 0;
4220 txdr_nfsv4time(&verstime, tl);
4222 NFSEXITCODE2(0, nd);
4226 free(clp->lc_req.nr_nam, M_SONAME);
4227 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4228 free(clp->lc_stateid, M_NFSDCLIENT);
4229 free(clp, M_NFSDCLIENT);
4231 NFSEXITCODE2(error, nd);
4236 * nfsv4 create session service
4239 nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram,
4240 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4244 nfsquad_t clientid, confirm;
4245 struct nfsdsession *sep = NULL;
4247 struct thread *p = curthread;
4249 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4250 nd->nd_repstat = NFSERR_WRONGSEC;
4253 sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession),
4254 M_NFSDSESSION, M_WAITOK | M_ZERO);
4255 sep->sess_refcnt = 1;
4256 mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF);
4257 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
4258 clientid.lval[0] = *tl++;
4259 clientid.lval[1] = *tl++;
4260 confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++);
4261 sep->sess_crflags = fxdr_unsigned(uint32_t, *tl);
4262 /* Persistent sessions and RDMA are not supported. */
4263 sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN;
4265 /* Fore channel attributes. */
4266 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4267 tl++; /* Header pad always 0. */
4268 sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++);
4269 if (sep->sess_maxreq > sb_max_adj - NFS_MAXXDR) {
4270 sep->sess_maxreq = sb_max_adj - NFS_MAXXDR;
4271 printf("Consider increasing kern.ipc.maxsockbuf\n");
4273 sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++);
4274 if (sep->sess_maxresp > sb_max_adj - NFS_MAXXDR) {
4275 sep->sess_maxresp = sb_max_adj - NFS_MAXXDR;
4276 printf("Consider increasing kern.ipc.maxsockbuf\n");
4278 sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++);
4279 sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++);
4280 sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++);
4281 if (sep->sess_maxslots > NFSV4_SLOTS)
4282 sep->sess_maxslots = NFSV4_SLOTS;
4283 rdmacnt = fxdr_unsigned(uint32_t, *tl);
4285 nd->nd_repstat = NFSERR_BADXDR;
4287 } else if (rdmacnt == 1)
4288 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4290 /* Back channel attributes. */
4291 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4292 tl++; /* Header pad always 0. */
4293 sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++);
4294 sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++);
4295 sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++);
4296 sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++);
4297 sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++);
4298 rdmacnt = fxdr_unsigned(uint32_t, *tl);
4300 nd->nd_repstat = NFSERR_BADXDR;
4302 } else if (rdmacnt == 1)
4303 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4305 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4306 sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl);
4309 * nfsrv_getclient() searches the client list for a match and
4310 * returns the appropriate NFSERR status.
4312 nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW,
4313 NULL, sep, confirm, sep->sess_cbprogram, nd, p);
4314 if (nd->nd_repstat == 0) {
4315 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4316 NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID);
4317 NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED);
4318 *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */
4319 *tl++ = txdr_unsigned(sep->sess_crflags);
4321 /* Fore channel attributes. */
4323 *tl++ = txdr_unsigned(sep->sess_maxreq);
4324 *tl++ = txdr_unsigned(sep->sess_maxresp);
4325 *tl++ = txdr_unsigned(sep->sess_maxrespcached);
4326 *tl++ = txdr_unsigned(sep->sess_maxops);
4327 *tl++ = txdr_unsigned(sep->sess_maxslots);
4328 *tl++ = txdr_unsigned(1);
4329 *tl++ = txdr_unsigned(0); /* No RDMA. */
4331 /* Back channel attributes. */
4333 *tl++ = txdr_unsigned(sep->sess_cbmaxreq);
4334 *tl++ = txdr_unsigned(sep->sess_cbmaxresp);
4335 *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached);
4336 *tl++ = txdr_unsigned(sep->sess_cbmaxops);
4337 *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots);
4338 *tl++ = txdr_unsigned(1);
4339 *tl = txdr_unsigned(0); /* No RDMA. */
4342 if (nd->nd_repstat != 0 && sep != NULL)
4343 free(sep, M_NFSDSESSION);
4344 NFSEXITCODE2(error, nd);
4349 * nfsv4 sequence service
4352 nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram,
4353 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4356 uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid;
4357 int cache_this, error = 0;
4358 struct thread *p = curthread;
4360 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4361 nd->nd_repstat = NFSERR_WRONGSEC;
4364 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID);
4365 NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID);
4366 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4367 sequenceid = fxdr_unsigned(uint32_t, *tl++);
4368 nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++);
4369 highest_slotid = fxdr_unsigned(uint32_t, *tl++);
4370 if (*tl == newnfs_true)
4374 nd->nd_flag |= ND_HASSEQUENCE;
4375 nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid,
4376 &target_highest_slotid, cache_this, &sflags, p);
4377 if (nd->nd_repstat == 0) {
4378 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4379 NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID);
4380 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
4381 *tl++ = txdr_unsigned(sequenceid);
4382 *tl++ = txdr_unsigned(nd->nd_slotid);
4383 *tl++ = txdr_unsigned(highest_slotid);
4384 *tl++ = txdr_unsigned(target_highest_slotid);
4385 *tl = txdr_unsigned(sflags);
4388 NFSEXITCODE2(error, nd);
4393 * nfsv4 reclaim complete service
4396 nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram,
4397 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4400 int error = 0, onefs;
4402 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4403 nd->nd_repstat = NFSERR_WRONGSEC;
4406 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4408 * I believe that a ReclaimComplete with rca_one_fs == TRUE is only
4409 * to be used after a file system has been transferred to a different
4410 * file server. However, RFC5661 is somewhat vague w.r.t. this and
4411 * the ESXi 6.7 client does both a ReclaimComplete with rca_one_fs
4412 * == TRUE and one with ReclaimComplete with rca_one_fs == FALSE.
4413 * Therefore, just ignore the rca_one_fs == TRUE operation and return
4414 * NFS_OK without doing anything.
4417 if (*tl == newnfs_true)
4419 nd->nd_repstat = nfsrv_checkreclaimcomplete(nd, onefs);
4421 NFSEXITCODE2(error, nd);
4426 * nfsv4 destroy clientid service
4429 nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram,
4430 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4435 struct thread *p = curthread;
4437 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4438 nd->nd_repstat = NFSERR_WRONGSEC;
4441 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4442 clientid.lval[0] = *tl++;
4443 clientid.lval[1] = *tl;
4444 nd->nd_repstat = nfsrv_destroyclient(clientid, p);
4446 NFSEXITCODE2(error, nd);
4451 * nfsv4 bind connection to session service
4454 nfsrvd_bindconnsess(struct nfsrv_descript *nd, __unused int isdgram,
4455 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4458 uint8_t sessid[NFSX_V4SESSIONID];
4459 int error = 0, foreaft;
4461 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4462 nd->nd_repstat = NFSERR_WRONGSEC;
4465 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED);
4466 NFSBCOPY(tl, sessid, NFSX_V4SESSIONID);
4467 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
4468 foreaft = fxdr_unsigned(int, *tl++);
4469 if (*tl == newnfs_true) {
4470 /* RDMA is not supported. */
4471 nd->nd_repstat = NFSERR_NOTSUPP;
4475 nd->nd_repstat = nfsrv_bindconnsess(nd, sessid, &foreaft);
4476 if (nd->nd_repstat == 0) {
4477 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 *
4479 NFSBCOPY(sessid, tl, NFSX_V4SESSIONID);
4480 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
4481 *tl++ = txdr_unsigned(foreaft);
4485 NFSEXITCODE2(error, nd);
4490 * nfsv4 destroy session service
4493 nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram,
4494 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4496 uint8_t *cp, sessid[NFSX_V4SESSIONID];
4499 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4500 nd->nd_repstat = NFSERR_WRONGSEC;
4503 NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID);
4504 NFSBCOPY(cp, sessid, NFSX_V4SESSIONID);
4505 nd->nd_repstat = nfsrv_destroysession(nd, sessid);
4507 NFSEXITCODE2(error, nd);
4512 * nfsv4 free stateid service
4515 nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram,
4516 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4519 nfsv4stateid_t stateid;
4521 struct thread *p = curthread;
4523 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4524 nd->nd_repstat = NFSERR_WRONGSEC;
4527 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
4528 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4529 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4532 * For the special stateid of other all 0s and seqid == 1, set the
4533 * stateid to the current stateid, if it is set.
4535 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4536 stateid.other[1] == 0 && stateid.other[2] == 0) {
4537 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4538 stateid = nd->nd_curstateid;
4541 nd->nd_repstat = NFSERR_BADSTATEID;
4546 nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p);
4548 /* If the current stateid has been free'd, unset it. */
4549 if (nd->nd_repstat == 0 && (nd->nd_flag & ND_CURSTATEID) != 0 &&
4550 stateid.other[0] == nd->nd_curstateid.other[0] &&
4551 stateid.other[1] == nd->nd_curstateid.other[1] &&
4552 stateid.other[2] == nd->nd_curstateid.other[2])
4553 nd->nd_flag &= ~ND_CURSTATEID;
4555 NFSEXITCODE2(error, nd);
4560 * nfsv4 layoutget service
4563 nfsrvd_layoutget(struct nfsrv_descript *nd, __unused int isdgram,
4564 vnode_t vp, struct nfsexstuff *exp)
4567 nfsv4stateid_t stateid;
4568 int error = 0, layoutlen, layouttype, iomode, maxcnt, retonclose;
4569 uint64_t offset, len, minlen;
4571 struct thread *p = curthread;
4573 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4574 nd->nd_repstat = NFSERR_WRONGSEC;
4577 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
4579 tl++; /* Signal layout available. Ignore for now. */
4580 layouttype = fxdr_unsigned(int, *tl++);
4581 iomode = fxdr_unsigned(int, *tl++);
4582 offset = fxdr_hyper(tl); tl += 2;
4583 len = fxdr_hyper(tl); tl += 2;
4584 minlen = fxdr_hyper(tl); tl += 2;
4585 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4586 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4587 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4588 maxcnt = fxdr_unsigned(int, *tl);
4589 NFSD_DEBUG(4, "layoutget ltyp=%d iom=%d off=%ju len=%ju mlen=%ju\n",
4590 layouttype, iomode, (uintmax_t)offset, (uintmax_t)len,
4593 (minlen != UINT64_MAX && offset + minlen < offset) ||
4594 (len != UINT64_MAX && offset + len < offset)) {
4595 nd->nd_repstat = NFSERR_INVAL;
4600 * For the special stateid of other all 0s and seqid == 1, set the
4601 * stateid to the current stateid, if it is set.
4603 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4604 stateid.other[1] == 0 && stateid.other[2] == 0) {
4605 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4606 stateid = nd->nd_curstateid;
4609 nd->nd_repstat = NFSERR_BADSTATEID;
4615 if (layouttype == NFSLAYOUT_NFSV4_1_FILES && nfsrv_maxpnfsmirror == 1)
4616 layp = malloc(NFSX_V4FILELAYOUT, M_TEMP, M_WAITOK);
4617 else if (layouttype == NFSLAYOUT_FLEXFILE)
4618 layp = malloc(NFSX_V4FLEXLAYOUT(nfsrv_maxpnfsmirror), M_TEMP,
4621 nd->nd_repstat = NFSERR_UNKNLAYOUTTYPE;
4623 nd->nd_repstat = nfsrv_layoutget(nd, vp, exp, layouttype,
4624 &iomode, &offset, &len, minlen, &stateid, maxcnt,
4625 &retonclose, &layoutlen, layp, nd->nd_cred, p);
4626 NFSD_DEBUG(4, "nfsrv_layoutget stat=%u layoutlen=%d\n", nd->nd_repstat,
4628 if (nd->nd_repstat == 0) {
4629 /* For NFSv4.1, set the Current StateID. */
4630 if ((nd->nd_flag & ND_NFSV41) != 0) {
4631 nd->nd_curstateid = stateid;
4632 nd->nd_flag |= ND_CURSTATEID;
4634 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_STATEID +
4636 *tl++ = txdr_unsigned(retonclose);
4637 *tl++ = txdr_unsigned(stateid.seqid);
4638 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
4639 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4640 *tl++ = txdr_unsigned(1); /* Only returns one layout. */
4641 txdr_hyper(offset, tl); tl += 2;
4642 txdr_hyper(len, tl); tl += 2;
4643 *tl++ = txdr_unsigned(iomode);
4644 *tl = txdr_unsigned(layouttype);
4645 nfsm_strtom(nd, layp, layoutlen);
4646 } else if (nd->nd_repstat == NFSERR_LAYOUTTRYLATER) {
4647 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4653 NFSEXITCODE2(error, nd);
4658 * nfsv4 layoutcommit service
4661 nfsrvd_layoutcommit(struct nfsrv_descript *nd, __unused int isdgram,
4662 vnode_t vp, struct nfsexstuff *exp)
4665 nfsv4stateid_t stateid;
4666 int error = 0, hasnewoff, hasnewmtime, layouttype, maxcnt, reclaim;
4668 uint64_t offset, len, newoff = 0, newsize;
4669 struct timespec newmtime;
4671 struct thread *p = curthread;
4674 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4675 nd->nd_repstat = NFSERR_WRONGSEC;
4678 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + 2 * NFSX_HYPER +
4680 offset = fxdr_hyper(tl); tl += 2;
4681 len = fxdr_hyper(tl); tl += 2;
4682 reclaim = fxdr_unsigned(int, *tl++);
4683 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4684 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4685 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4687 * For the special stateid of other all 0s and seqid == 1, set the
4688 * stateid to the current stateid, if it is set.
4690 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4691 stateid.other[1] == 0 && stateid.other[2] == 0) {
4692 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4693 stateid = nd->nd_curstateid;
4696 nd->nd_repstat = NFSERR_BADSTATEID;
4701 hasnewoff = fxdr_unsigned(int, *tl);
4702 if (hasnewoff != 0) {
4703 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
4704 newoff = fxdr_hyper(tl); tl += 2;
4706 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4707 hasnewmtime = fxdr_unsigned(int, *tl);
4708 if (hasnewmtime != 0) {
4709 NFSM_DISSECT(tl, uint32_t *, NFSX_V4TIME + 2 * NFSX_UNSIGNED);
4710 fxdr_nfsv4time(tl, &newmtime);
4711 tl += (NFSX_V4TIME / NFSX_UNSIGNED);
4713 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4714 layouttype = fxdr_unsigned(int, *tl++);
4715 maxcnt = fxdr_unsigned(int, *tl);
4717 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
4718 error = nfsrv_mtostr(nd, layp, maxcnt);
4722 nd->nd_repstat = nfsrv_layoutcommit(nd, vp, layouttype, hasnewoff,
4723 newoff, offset, len, hasnewmtime, &newmtime, reclaim, &stateid,
4724 maxcnt, layp, &hasnewsize, &newsize, nd->nd_cred, p);
4725 NFSD_DEBUG(4, "nfsrv_layoutcommit stat=%u\n", nd->nd_repstat);
4726 if (nd->nd_repstat == 0) {
4727 if (hasnewsize != 0) {
4728 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER);
4729 *tl++ = newnfs_true;
4730 txdr_hyper(newsize, tl);
4732 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4739 NFSEXITCODE2(error, nd);
4744 * nfsv4 layoutreturn service
4747 nfsrvd_layoutreturn(struct nfsrv_descript *nd, __unused int isdgram,
4748 vnode_t vp, struct nfsexstuff *exp)
4750 uint32_t *tl, *layp;
4751 nfsv4stateid_t stateid;
4752 int error = 0, fnd, kind, layouttype, iomode, maxcnt, reclaim;
4753 uint64_t offset, len;
4754 struct thread *p = curthread;
4757 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4758 nd->nd_repstat = NFSERR_WRONGSEC;
4761 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4763 layouttype = fxdr_unsigned(int, *tl++);
4764 iomode = fxdr_unsigned(int, *tl++);
4765 kind = fxdr_unsigned(int, *tl);
4766 NFSD_DEBUG(4, "layoutreturn recl=%d ltyp=%d iom=%d kind=%d\n", reclaim,
4767 layouttype, iomode, kind);
4768 if (kind == NFSV4LAYOUTRET_FILE) {
4769 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
4771 offset = fxdr_hyper(tl); tl += 2;
4772 len = fxdr_hyper(tl); tl += 2;
4773 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4774 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4775 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4778 * For the special stateid of other all 0s and seqid == 1, set
4779 * the stateid to the current stateid, if it is set.
4781 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4782 stateid.other[1] == 0 && stateid.other[2] == 0) {
4783 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4784 stateid = nd->nd_curstateid;
4787 nd->nd_repstat = NFSERR_BADSTATEID;
4792 maxcnt = fxdr_unsigned(int, *tl);
4794 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
4795 error = nfsrv_mtostr(nd, (char *)layp, maxcnt);
4800 if (reclaim == newnfs_true) {
4801 nd->nd_repstat = NFSERR_INVAL;
4807 nd->nd_repstat = nfsrv_layoutreturn(nd, vp, layouttype, iomode,
4808 offset, len, reclaim, kind, &stateid, maxcnt, layp, &fnd,
4810 NFSD_DEBUG(4, "nfsrv_layoutreturn stat=%u fnd=%d\n", nd->nd_repstat,
4812 if (nd->nd_repstat == 0) {
4813 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4816 NFSM_BUILD(tl, uint32_t *, NFSX_STATEID);
4817 *tl++ = txdr_unsigned(stateid.seqid);
4818 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
4825 NFSEXITCODE2(error, nd);
4830 * nfsv4 layout error service
4833 nfsrvd_layouterror(struct nfsrv_descript *nd, __unused int isdgram,
4834 vnode_t vp, struct nfsexstuff *exp)
4837 nfsv4stateid_t stateid;
4838 int cnt, error = 0, i, stat;
4840 char devid[NFSX_V4DEVICEID];
4841 uint64_t offset, len;
4843 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4844 nd->nd_repstat = NFSERR_WRONGSEC;
4847 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
4849 offset = fxdr_hyper(tl); tl += 2;
4850 len = fxdr_hyper(tl); tl += 2;
4851 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4852 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4853 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4854 cnt = fxdr_unsigned(int, *tl);
4855 NFSD_DEBUG(4, "layouterror off=%ju len=%ju cnt=%d\n", (uintmax_t)offset,
4856 (uintmax_t)len, cnt);
4858 * For the special stateid of other all 0s and seqid == 1, set
4859 * the stateid to the current stateid, if it is set.
4861 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4862 stateid.other[1] == 0 && stateid.other[2] == 0) {
4863 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4864 stateid = nd->nd_curstateid;
4867 nd->nd_repstat = NFSERR_BADSTATEID;
4873 * Ignore offset, len and stateid for now.
4875 for (i = 0; i < cnt; i++) {
4876 NFSM_DISSECT(tl, uint32_t *, NFSX_V4DEVICEID + 2 *
4878 NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
4879 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
4880 stat = fxdr_unsigned(int, *tl++);
4881 opnum = fxdr_unsigned(int, *tl);
4882 NFSD_DEBUG(4, "nfsrvd_layouterr op=%d stat=%d\n", opnum, stat);
4884 * Except for NFSERR_ACCES and NFSERR_STALE errors,
4885 * disable the mirror.
4887 if (stat != NFSERR_ACCES && stat != NFSERR_STALE)
4888 nfsrv_delds(devid, curthread);
4892 NFSEXITCODE2(error, nd);
4897 * nfsv4 layout stats service
4900 nfsrvd_layoutstats(struct nfsrv_descript *nd, __unused int isdgram,
4901 vnode_t vp, struct nfsexstuff *exp)
4904 nfsv4stateid_t stateid;
4906 int layouttype __unused;
4907 char devid[NFSX_V4DEVICEID] __unused;
4908 uint64_t offset, len, readcount, readbytes, writecount, writebytes
4911 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4912 nd->nd_repstat = NFSERR_WRONGSEC;
4915 NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_HYPER + NFSX_STATEID +
4916 NFSX_V4DEVICEID + 2 * NFSX_UNSIGNED);
4917 offset = fxdr_hyper(tl); tl += 2;
4918 len = fxdr_hyper(tl); tl += 2;
4919 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4920 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4921 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4922 readcount = fxdr_hyper(tl); tl += 2;
4923 readbytes = fxdr_hyper(tl); tl += 2;
4924 writecount = fxdr_hyper(tl); tl += 2;
4925 writebytes = fxdr_hyper(tl); tl += 2;
4926 NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
4927 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
4928 layouttype = fxdr_unsigned(int, *tl++);
4929 cnt = fxdr_unsigned(int, *tl);
4930 error = nfsm_advance(nd, NFSM_RNDUP(cnt), -1);
4933 NFSD_DEBUG(4, "layoutstats cnt=%d\n", cnt);
4935 * For the special stateid of other all 0s and seqid == 1, set
4936 * the stateid to the current stateid, if it is set.
4938 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4939 stateid.other[1] == 0 && stateid.other[2] == 0) {
4940 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4941 stateid = nd->nd_curstateid;
4944 nd->nd_repstat = NFSERR_BADSTATEID;
4950 * No use for the stats for now.
4954 NFSEXITCODE2(error, nd);
4959 * nfsv4 io_advise service
4962 nfsrvd_ioadvise(struct nfsrv_descript *nd, __unused int isdgram,
4963 vnode_t vp, struct nfsexstuff *exp)
4966 nfsv4stateid_t stateid;
4971 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4972 nd->nd_repstat = NFSERR_WRONGSEC;
4975 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
4976 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4977 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4978 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4979 offset = fxdr_hyper(tl); tl += 2;
4980 len = fxdr_hyper(tl);
4981 error = nfsrv_getattrbits(nd, &hints, NULL, NULL);
4985 * For the special stateid of other all 0s and seqid == 1, set
4986 * the stateid to the current stateid, if it is set.
4988 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4989 stateid.other[1] == 0 && stateid.other[2] == 0) {
4990 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4991 stateid = nd->nd_curstateid;
4994 nd->nd_repstat = NFSERR_BADSTATEID;
5000 nd->nd_repstat = NFSERR_INVAL;
5005 if (vp->v_type != VREG) {
5006 if (vp->v_type == VDIR)
5007 nd->nd_repstat = NFSERR_ISDIR;
5009 nd->nd_repstat = NFSERR_WRONGTYPE;
5014 * For now, we can only handle WILLNEED and DONTNEED and don't use
5017 if ((NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED) &&
5018 !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED)) ||
5019 (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED) &&
5020 !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED))) {
5022 if (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED)) {
5023 ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_WILLNEED);
5024 NFSZERO_ATTRBIT(&hints);
5026 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED);
5028 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
5030 ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_DONTNEED);
5031 NFSZERO_ATTRBIT(&hints);
5033 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED);
5035 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
5039 NFSZERO_ATTRBIT(&hints);
5040 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
5043 nfsrv_putattrbit(nd, &hints);
5044 NFSEXITCODE2(error, nd);
5048 NFSEXITCODE2(error, nd);
5053 * nfsv4 getdeviceinfo service
5056 nfsrvd_getdevinfo(struct nfsrv_descript *nd, __unused int isdgram,
5057 __unused vnode_t vp, __unused struct nfsexstuff *exp)
5059 uint32_t *tl, maxcnt, notify[NFSV4_NOTIFYBITMAP];
5060 int cnt, devaddrlen, error = 0, i, layouttype;
5061 char devid[NFSX_V4DEVICEID], *devaddr;
5064 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5065 nd->nd_repstat = NFSERR_WRONGSEC;
5068 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_V4DEVICEID);
5069 NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
5070 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5071 layouttype = fxdr_unsigned(int, *tl++);
5072 maxcnt = fxdr_unsigned(uint32_t, *tl++);
5073 cnt = fxdr_unsigned(int, *tl);
5074 NFSD_DEBUG(4, "getdevinfo ltyp=%d maxcnt=%u bitcnt=%d\n", layouttype,
5076 if (cnt > NFSV4_NOTIFYBITMAP || cnt < 0) {
5077 nd->nd_repstat = NFSERR_INVAL;
5081 NFSM_DISSECT(tl, uint32_t *, cnt * NFSX_UNSIGNED);
5082 for (i = 0; i < cnt; i++)
5083 notify[i] = fxdr_unsigned(uint32_t, *tl++);
5085 for (i = cnt; i < NFSV4_NOTIFYBITMAP; i++)
5089 * Check that the device id is not stale. Device ids are recreated
5090 * each time the nfsd threads are restarted.
5092 NFSBCOPY(devid, &dev_time, sizeof(dev_time));
5093 if (dev_time != nfsdev_time) {
5094 nd->nd_repstat = NFSERR_NOENT;
5098 /* Look for the device id. */
5099 nd->nd_repstat = nfsrv_getdevinfo(devid, layouttype, &maxcnt,
5100 notify, &devaddrlen, &devaddr);
5101 NFSD_DEBUG(4, "nfsrv_getdevinfo stat=%u\n", nd->nd_repstat);
5102 if (nd->nd_repstat == 0) {
5103 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5104 *tl = txdr_unsigned(layouttype);
5105 nfsm_strtom(nd, devaddr, devaddrlen);
5107 for (i = 0; i < NFSV4_NOTIFYBITMAP; i++) {
5111 NFSM_BUILD(tl, uint32_t *, (cnt + 1) * NFSX_UNSIGNED);
5112 *tl++ = txdr_unsigned(cnt);
5113 for (i = 0; i < cnt; i++)
5114 *tl++ = txdr_unsigned(notify[i]);
5115 } else if (nd->nd_repstat == NFSERR_TOOSMALL) {
5116 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5117 *tl = txdr_unsigned(maxcnt);
5120 NFSEXITCODE2(error, nd);
5125 * nfsv4 test stateid service
5128 nfsrvd_teststateid(struct nfsrv_descript *nd, __unused int isdgram,
5129 __unused vnode_t vp, __unused struct nfsexstuff *exp)
5132 nfsv4stateid_t *stateidp = NULL, *tstateidp;
5133 int cnt, error = 0, i, ret;
5134 struct thread *p = curthread;
5136 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5137 nd->nd_repstat = NFSERR_WRONGSEC;
5140 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5141 cnt = fxdr_unsigned(int, *tl);
5142 if (cnt <= 0 || cnt > 1024) {
5143 nd->nd_repstat = NFSERR_BADXDR;
5146 stateidp = mallocarray(cnt, sizeof(nfsv4stateid_t), M_TEMP, M_WAITOK);
5147 tstateidp = stateidp;
5148 for (i = 0; i < cnt; i++) {
5149 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
5150 tstateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
5151 NFSBCOPY(tl, tstateidp->other, NFSX_STATEIDOTHER);
5154 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5155 *tl = txdr_unsigned(cnt);
5156 tstateidp = stateidp;
5157 for (i = 0; i < cnt; i++) {
5158 ret = nfsrv_teststateid(nd, tstateidp, p);
5159 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5160 *tl = txdr_unsigned(ret);
5164 free(stateidp, M_TEMP);
5165 NFSEXITCODE2(error, nd);
5170 * nfs allocate service
5173 nfsrvd_allocate(struct nfsrv_descript *nd, __unused int isdgram,
5174 vnode_t vp, struct nfsexstuff *exp)
5177 struct nfsvattr forat;
5178 int error = 0, forat_ret = 1, gotproxystateid;
5180 struct nfsstate st, *stp = &st;
5181 struct nfslock lo, *lop = &lo;
5182 nfsv4stateid_t stateid;
5184 nfsattrbit_t attrbits;
5186 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5187 nd->nd_repstat = NFSERR_WRONGSEC;
5190 gotproxystateid = 0;
5191 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
5192 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5193 lop->lo_flags = NFSLCK_WRITE;
5194 stp->ls_ownerlen = 0;
5196 stp->ls_uid = nd->nd_cred->cr_uid;
5197 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
5198 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
5199 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
5200 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
5201 if ((nd->nd_flag & ND_NFSV41) != 0)
5202 clientid.qval = nd->nd_clientid.qval;
5203 else if (nd->nd_clientid.qval != clientid.qval)
5204 printf("EEK2 multiple clids\n");
5206 if ((nd->nd_flag & ND_NFSV41) != 0)
5207 printf("EEK! no clientid from session\n");
5208 nd->nd_flag |= ND_IMPLIEDCLID;
5209 nd->nd_clientid.qval = clientid.qval;
5211 stp->ls_stateid.other[2] = *tl++;
5213 * Don't allow this to be done for a DS.
5215 if ((nd->nd_flag & ND_DSSERVER) != 0)
5216 nd->nd_repstat = NFSERR_NOTSUPP;
5217 /* However, allow the proxy stateid. */
5218 if (stp->ls_stateid.seqid == 0xffffffff &&
5219 stp->ls_stateid.other[0] == 0x55555555 &&
5220 stp->ls_stateid.other[1] == 0x55555555 &&
5221 stp->ls_stateid.other[2] == 0x55555555)
5222 gotproxystateid = 1;
5223 off = fxdr_hyper(tl); tl += 2;
5224 lop->lo_first = off;
5225 len = fxdr_hyper(tl);
5226 lop->lo_end = off + len;
5228 * Paranoia, just in case it wraps around, which shouldn't
5229 * ever happen anyhow.
5231 if (nd->nd_repstat == 0 && (lop->lo_end < lop->lo_first || len <= 0))
5232 nd->nd_repstat = NFSERR_INVAL;
5234 if (nd->nd_repstat == 0 && vnode_vtype(vp) != VREG)
5235 nd->nd_repstat = NFSERR_WRONGTYPE;
5236 NFSZERO_ATTRBIT(&attrbits);
5237 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5238 forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits);
5239 if (nd->nd_repstat == 0)
5240 nd->nd_repstat = forat_ret;
5241 if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid ||
5242 NFSVNO_EXSTRICTACCESS(exp)))
5243 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp,
5244 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5246 if (nd->nd_repstat == 0 && gotproxystateid == 0)
5247 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
5248 &stateid, exp, nd, curthread);
5250 if (nd->nd_repstat == 0)
5251 nd->nd_repstat = nfsvno_allocate(vp, off, len, nd->nd_cred,
5254 NFSEXITCODE2(0, nd);
5258 NFSEXITCODE2(error, nd);
5266 nfsrvd_copy_file_range(struct nfsrv_descript *nd, __unused int isdgram,
5267 vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
5271 int cnt, error = 0, ret;
5272 off_t inoff, outoff;
5275 struct nfsstate inst, outst, *instp = &inst, *outstp = &outst;
5276 struct nfslock inlo, outlo, *inlop = &inlo, *outlop = &outlo;
5278 nfsv4stateid_t stateid;
5279 nfsattrbit_t attrbits;
5280 void *rl_rcookie, *rl_wcookie;
5282 rl_rcookie = rl_wcookie = NULL;
5283 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5284 nd->nd_repstat = NFSERR_WRONGSEC;
5287 if (nfsrv_devidcnt > 0) {
5289 * For a pNFS server, reply NFSERR_NOTSUPP so that the client
5290 * will do the copy via I/O on the DS(s).
5292 nd->nd_repstat = NFSERR_NOTSUPP;
5296 /* Copying a byte range within the same file is not allowed. */
5297 nd->nd_repstat = NFSERR_INVAL;
5300 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_STATEID + 3 * NFSX_HYPER +
5302 instp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
5303 inlop->lo_flags = NFSLCK_READ;
5304 instp->ls_ownerlen = 0;
5305 instp->ls_op = NULL;
5306 instp->ls_uid = nd->nd_cred->cr_uid;
5307 instp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5308 clientid.lval[0] = instp->ls_stateid.other[0] = *tl++;
5309 clientid.lval[1] = instp->ls_stateid.other[1] = *tl++;
5310 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0)
5311 clientid.qval = nd->nd_clientid.qval;
5312 instp->ls_stateid.other[2] = *tl++;
5313 outstp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5314 outlop->lo_flags = NFSLCK_WRITE;
5315 outstp->ls_ownerlen = 0;
5316 outstp->ls_op = NULL;
5317 outstp->ls_uid = nd->nd_cred->cr_uid;
5318 outstp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5319 outstp->ls_stateid.other[0] = *tl++;
5320 outstp->ls_stateid.other[1] = *tl++;
5321 outstp->ls_stateid.other[2] = *tl++;
5322 inoff = fxdr_hyper(tl); tl += 2;
5323 inlop->lo_first = inoff;
5324 outoff = fxdr_hyper(tl); tl += 2;
5325 outlop->lo_first = outoff;
5326 len = fxdr_hyper(tl); tl += 2;
5328 /* len == 0 means to EOF. */
5329 inlop->lo_end = OFF_MAX;
5330 outlop->lo_end = OFF_MAX;
5332 inlop->lo_end = inlop->lo_first + len;
5333 outlop->lo_end = outlop->lo_first + len;
5337 * At this time only consecutive, synchronous copy is supported,
5338 * so ca_consecutive and ca_synchronous can be ignored.
5342 cnt = fxdr_unsigned(int, *tl);
5343 if ((nd->nd_flag & ND_DSSERVER) != 0 || cnt != 0)
5344 nd->nd_repstat = NFSERR_NOTSUPP;
5345 if (nd->nd_repstat == 0 && (inoff > OFF_MAX || outoff > OFF_MAX ||
5346 inlop->lo_end > OFF_MAX || outlop->lo_end > OFF_MAX ||
5347 inlop->lo_end < inlop->lo_first || outlop->lo_end <
5349 nd->nd_repstat = NFSERR_INVAL;
5351 if (nd->nd_repstat == 0 && vnode_vtype(vp) != VREG)
5352 nd->nd_repstat = NFSERR_WRONGTYPE;
5354 /* Check permissions for the input file. */
5355 NFSZERO_ATTRBIT(&attrbits);
5356 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5357 ret = nfsvno_getattr(vp, &at, nd, curthread, 1, &attrbits);
5358 if (nd->nd_repstat == 0)
5359 nd->nd_repstat = ret;
5360 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5361 NFSVNO_EXSTRICTACCESS(exp)))
5362 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp,
5363 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5365 if (nd->nd_repstat == 0)
5366 nd->nd_repstat = nfsrv_lockctrl(vp, &instp, &inlop, NULL,
5367 clientid, &stateid, exp, nd, curthread);
5369 if (nd->nd_repstat != 0)
5372 error = NFSVOPLOCK(tovp, LK_SHARED);
5375 if (vnode_vtype(tovp) != VREG)
5376 nd->nd_repstat = NFSERR_WRONGTYPE;
5378 /* For the output file, we only need the Owner attribute. */
5379 ret = nfsvno_getattr(tovp, &at, nd, curthread, 1, &attrbits);
5380 if (nd->nd_repstat == 0)
5381 nd->nd_repstat = ret;
5382 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5383 NFSVNO_EXSTRICTACCESS(exp)))
5384 nd->nd_repstat = nfsvno_accchk(tovp, VWRITE, nd->nd_cred, toexp,
5385 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5387 if (nd->nd_repstat == 0)
5388 nd->nd_repstat = nfsrv_lockctrl(tovp, &outstp, &outlop, NULL,
5389 clientid, &stateid, toexp, nd, curthread);
5392 /* Range lock the byte ranges for both invp and outvp. */
5393 if (nd->nd_repstat == 0) {
5396 rl_wcookie = vn_rangelock_wlock(tovp, outoff,
5398 rl_rcookie = vn_rangelock_tryrlock(vp, inoff,
5401 rl_wcookie = vn_rangelock_wlock(tovp, outoff,
5403 rl_rcookie = vn_rangelock_tryrlock(vp, inoff,
5406 if (rl_rcookie != NULL)
5408 vn_rangelock_unlock(tovp, rl_wcookie);
5410 rl_rcookie = vn_rangelock_rlock(vp, inoff,
5413 rl_rcookie = vn_rangelock_rlock(vp, inoff,
5415 vn_rangelock_unlock(vp, rl_rcookie);
5418 error = NFSVOPLOCK(vp, LK_SHARED);
5420 ret = nfsvno_getattr(vp, &at, nd, curthread, 1, NULL);
5423 * Since invp is range locked, na_size should
5426 if (len == 0 && at.na_size > inoff) {
5428 * If len == 0, set it based on invp's
5429 * size. If offset is past EOF, just
5432 len = at.na_size - inoff;
5433 } else if (nfsrv_linux42server == 0 &&
5434 inoff + len > at.na_size) {
5436 * RFC-7862 says that NFSERR_INVAL must
5437 * be returned when inoff + len exceeds
5438 * the file size, however the NFSv4.2
5439 * Linux client likes to do this, so
5440 * only check if nfsrv_linux42server
5443 nd->nd_repstat = NFSERR_INVAL;
5447 if (ret != 0 && nd->nd_repstat == 0)
5448 nd->nd_repstat = ret;
5449 } else if (nd->nd_repstat == 0)
5450 nd->nd_repstat = error;
5454 * Do the actual copy to an upper limit of vfs.nfs.maxcopyrange.
5455 * This limit is applied to ensure that the RPC replies in a
5458 if (len > nfs_maxcopyrange)
5459 xfer = nfs_maxcopyrange;
5462 if (nd->nd_repstat == 0) {
5463 nd->nd_repstat = vn_copy_file_range(vp, &inoff, tovp, &outoff,
5464 &xfer, 0, nd->nd_cred, nd->nd_cred, NULL);
5465 if (nd->nd_repstat == 0)
5469 /* Unlock the ranges. */
5470 if (rl_rcookie != NULL)
5471 vn_rangelock_unlock(vp, rl_rcookie);
5472 if (rl_wcookie != NULL)
5473 vn_rangelock_unlock(tovp, rl_wcookie);
5475 if (nd->nd_repstat == 0) {
5476 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_HYPER +
5478 *tl++ = txdr_unsigned(0); /* No callback ids. */
5479 txdr_hyper(len, tl); tl += 2;
5480 *tl++ = txdr_unsigned(NFSWRITE_UNSTABLE);
5481 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
5482 *tl++ = txdr_unsigned(nfsboottime.tv_usec);
5483 *tl++ = newnfs_true;
5489 NFSEXITCODE2(error, nd);
5494 NFSEXITCODE2(error, nd);
5502 nfsrvd_seek(struct nfsrv_descript *nd, __unused int isdgram,
5503 vnode_t vp, struct nfsexstuff *exp)
5507 int content, error = 0;
5510 nfsattrbit_t attrbits;
5513 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5514 nd->nd_repstat = NFSERR_WRONGSEC;
5517 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + NFSX_HYPER + NFSX_UNSIGNED);
5518 /* Ignore the stateid for now. */
5519 tl += (NFSX_STATEID / NFSX_UNSIGNED);
5520 off = fxdr_hyper(tl); tl += 2;
5521 content = fxdr_unsigned(int, *tl);
5522 if (content == NFSV4CONTENT_DATA)
5524 else if (content == NFSV4CONTENT_HOLE)
5527 nd->nd_repstat = NFSERR_BADXDR;
5528 if (nd->nd_repstat == 0 && vnode_vtype(vp) == VDIR)
5529 nd->nd_repstat = NFSERR_ISDIR;
5530 if (nd->nd_repstat == 0 && vnode_vtype(vp) != VREG)
5531 nd->nd_repstat = NFSERR_WRONGTYPE;
5532 if (nd->nd_repstat == 0 && off < 0)
5533 nd->nd_repstat = NFSERR_NXIO;
5534 if (nd->nd_repstat == 0) {
5535 /* Check permissions for the input file. */
5536 NFSZERO_ATTRBIT(&attrbits);
5537 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5538 nd->nd_repstat = nfsvno_getattr(vp, &at, nd, curthread, 1,
5541 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5542 NFSVNO_EXSTRICTACCESS(exp)))
5543 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp,
5544 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5546 if (nd->nd_repstat != 0)
5549 /* nfsvno_seek() unlocks and vrele()s the vp. */
5550 nd->nd_repstat = nfsvno_seek(nd, vp, cmd, &off, content, &eof,
5551 nd->nd_cred, curthread);
5552 if (nd->nd_repstat == 0 && eof && content == NFSV4CONTENT_DATA &&
5553 nfsrv_linux42server != 0)
5554 nd->nd_repstat = NFSERR_NXIO;
5555 if (nd->nd_repstat == 0) {
5556 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER);
5558 *tl++ = newnfs_true;
5560 *tl++ = newnfs_false;
5561 txdr_hyper(off, tl);
5563 NFSEXITCODE2(error, nd);
5567 NFSEXITCODE2(error, nd);
5572 * nfs get extended attribute service
5575 nfsrvd_getxattr(struct nfsrv_descript *nd, __unused int isdgram,
5576 vnode_t vp, __unused struct nfsexstuff *exp)
5579 struct mbuf *mp = NULL, *mpend = NULL;
5582 struct thread *p = curthread;
5586 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5587 nd->nd_repstat = NFSERR_WRONGSEC;
5590 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5591 len = fxdr_unsigned(int, *tl);
5593 nd->nd_repstat = NFSERR_BADXDR;
5596 if (len > EXTATTR_MAXNAMELEN) {
5597 nd->nd_repstat = NFSERR_NOXATTR;
5600 name = malloc(len + 1, M_TEMP, M_WAITOK);
5601 nd->nd_repstat = nfsrv_mtostr(nd, name, len);
5602 if (nd->nd_repstat == 0)
5603 nd->nd_repstat = nfsvno_getxattr(vp, name,
5604 nd->nd_maxresp, nd->nd_cred, nd->nd_flag,
5605 nd->nd_maxextsiz, p, &mp, &mpend, &len);
5606 if (nd->nd_repstat == ENOATTR)
5607 nd->nd_repstat = NFSERR_NOXATTR;
5608 else if (nd->nd_repstat == EOPNOTSUPP)
5609 nd->nd_repstat = NFSERR_NOTSUPP;
5610 if (nd->nd_repstat == 0) {
5611 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5612 *tl = txdr_unsigned(len);
5614 nd->nd_mb->m_next = mp;
5616 if ((mpend->m_flags & M_EXTPG) != 0) {
5617 nd->nd_flag |= ND_EXTPG;
5618 nd->nd_bextpg = mpend->m_epg_npgs - 1;
5619 nd->nd_bpos = (char *)(void *)
5620 PHYS_TO_DMAP(mpend->m_epg_pa[nd->nd_bextpg]);
5621 off = (nd->nd_bextpg == 0) ?
5622 mpend->m_epg_1st_off : 0;
5623 nd->nd_bpos += off + mpend->m_epg_last_len;
5624 nd->nd_bextpgsiz = PAGE_SIZE -
5625 mpend->m_epg_last_len - off;
5627 nd->nd_bpos = mtod(mpend, char *) +
5634 if (nd->nd_repstat == 0)
5635 nd->nd_repstat = error;
5637 NFSEXITCODE2(0, nd);
5642 * nfs set extended attribute service
5645 nfsrvd_setxattr(struct nfsrv_descript *nd, __unused int isdgram,
5646 vnode_t vp, __unused struct nfsexstuff *exp)
5649 struct nfsvattr ova, nva;
5650 nfsattrbit_t attrbits;
5651 int error, len, opt;
5654 struct thread *p = curthread;
5658 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5659 nd->nd_repstat = NFSERR_WRONGSEC;
5662 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
5663 opt = fxdr_unsigned(int, *tl++);
5664 len = fxdr_unsigned(int, *tl);
5666 nd->nd_repstat = NFSERR_BADXDR;
5669 if (len > EXTATTR_MAXNAMELEN) {
5670 nd->nd_repstat = NFSERR_NOXATTR;
5673 name = malloc(len + 1, M_TEMP, M_WAITOK);
5674 error = nfsrv_mtostr(nd, name, len);
5677 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5678 len = fxdr_unsigned(int, *tl);
5679 if (len < 0 || len > IOSIZE_MAX) {
5680 nd->nd_repstat = NFSERR_XATTR2BIG;
5684 case NFSV4SXATTR_CREATE:
5685 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL,
5686 &siz, nd->nd_cred, p);
5687 if (error != ENOATTR)
5688 nd->nd_repstat = NFSERR_EXIST;
5691 case NFSV4SXATTR_REPLACE:
5692 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL,
5693 &siz, nd->nd_cred, p);
5695 nd->nd_repstat = NFSERR_NOXATTR;
5697 case NFSV4SXATTR_EITHER:
5700 nd->nd_repstat = NFSERR_BADXDR;
5702 if (nd->nd_repstat != 0)
5705 /* Now, do the Set Extended attribute, with Change before and after. */
5706 NFSZERO_ATTRBIT(&attrbits);
5707 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
5708 nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits);
5709 if (nd->nd_repstat == 0) {
5710 nd->nd_repstat = nfsvno_setxattr(vp, name, len, nd->nd_md,
5711 nd->nd_dpos, nd->nd_cred, p);
5712 if (nd->nd_repstat == ENXIO)
5713 nd->nd_repstat = NFSERR_XATTR2BIG;
5715 if (nd->nd_repstat == 0 && len > 0)
5716 nd->nd_repstat = nfsm_advance(nd, NFSM_RNDUP(len), -1);
5717 if (nd->nd_repstat == 0)
5718 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
5719 if (nd->nd_repstat == 0) {
5720 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED);
5721 *tl++ = newnfs_true;
5722 txdr_hyper(ova.na_filerev, tl); tl += 2;
5723 txdr_hyper(nva.na_filerev, tl);
5728 if (nd->nd_repstat == 0)
5729 nd->nd_repstat = error;
5731 NFSEXITCODE2(0, nd);
5736 * nfs remove extended attribute service
5739 nfsrvd_rmxattr(struct nfsrv_descript *nd, __unused int isdgram,
5740 vnode_t vp, __unused struct nfsexstuff *exp)
5743 struct nfsvattr ova, nva;
5744 nfsattrbit_t attrbits;
5747 struct thread *p = curthread;
5751 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5752 nd->nd_repstat = NFSERR_WRONGSEC;
5755 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5756 len = fxdr_unsigned(int, *tl);
5758 nd->nd_repstat = NFSERR_BADXDR;
5761 if (len > EXTATTR_MAXNAMELEN) {
5762 nd->nd_repstat = NFSERR_NOXATTR;
5765 name = malloc(len + 1, M_TEMP, M_WAITOK);
5766 error = nfsrv_mtostr(nd, name, len);
5770 if ((nd->nd_flag & ND_IMPLIEDCLID) == 0) {
5771 printf("EEK! nfsrvd_rmxattr: no implied clientid\n");
5772 error = NFSERR_NOXATTR;
5776 * Now, do the Remove Extended attribute, with Change before and
5779 NFSZERO_ATTRBIT(&attrbits);
5780 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
5781 nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits);
5782 if (nd->nd_repstat == 0) {
5783 nd->nd_repstat = nfsvno_rmxattr(nd, vp, name, nd->nd_cred, p);
5784 if (nd->nd_repstat == ENOATTR)
5785 nd->nd_repstat = NFSERR_NOXATTR;
5787 if (nd->nd_repstat == 0)
5788 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
5789 if (nd->nd_repstat == 0) {
5790 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED);
5791 *tl++ = newnfs_true;
5792 txdr_hyper(ova.na_filerev, tl); tl += 2;
5793 txdr_hyper(nva.na_filerev, tl);
5798 if (nd->nd_repstat == 0)
5799 nd->nd_repstat = error;
5801 NFSEXITCODE2(0, nd);
5806 * nfs list extended attribute service
5809 nfsrvd_listxattr(struct nfsrv_descript *nd, __unused int isdgram,
5810 vnode_t vp, __unused struct nfsexstuff *exp)
5812 uint32_t cnt, *tl, len, len2, i, pos, retlen;
5814 uint64_t cookie, cookie2;
5817 struct thread *p = curthread;
5821 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
5822 nd->nd_repstat = NFSERR_WRONGSEC;
5825 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
5827 * The cookie doesn't need to be in net byte order, but FreeBSD
5828 * does so to make it more readable in packet traces.
5830 cookie = fxdr_hyper(tl); tl += 2;
5831 len = fxdr_unsigned(uint32_t, *tl);
5832 if (len == 0 || cookie >= IOSIZE_MAX) {
5833 nd->nd_repstat = NFSERR_BADXDR;
5836 if (len > nd->nd_maxresp - NFS_MAXXDR)
5837 len = nd->nd_maxresp - NFS_MAXXDR;
5839 nd->nd_repstat = nfsvno_listxattr(vp, cookie, nd->nd_cred, p, &buf,
5841 if (nd->nd_repstat == EOPNOTSUPP)
5842 nd->nd_repstat = NFSERR_NOTSUPP;
5843 if (nd->nd_repstat == 0) {
5844 cookie2 = cookie + len;
5845 if (cookie2 < cookie)
5846 nd->nd_repstat = NFSERR_BADXDR;
5848 if (nd->nd_repstat == 0) {
5849 /* Now copy the entries out. */
5850 retlen = NFSX_HYPER + 2 * NFSX_UNSIGNED;
5851 if (len == 0 && retlen <= len2) {
5852 /* The cookie was at eof. */
5853 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 *
5855 txdr_hyper(cookie2, tl); tl += 2;
5856 *tl++ = txdr_unsigned(0);
5861 /* Sanity check the cookie. */
5862 for (pos = 0; pos < len; pos += (i + 1)) {
5867 if (pos != cookie) {
5868 nd->nd_repstat = NFSERR_INVAL;
5872 /* Loop around copying the entrie(s) out. */
5876 while (i < len && len2 >= retlen + NFSM_RNDUP(i) +
5879 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER +
5881 txdr_hyper(cookie2, tl); tl += 2;
5883 retlen += nfsm_strtom(nd, &buf[pos + 1], i);
5890 * eof is set true/false by nfsvno_listxattr(), but if we
5891 * can't copy all entries returned by nfsvno_listxattr(),
5892 * we are not at eof.
5897 /* *tl is set above. */
5898 *tl = txdr_unsigned(cnt);
5899 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5905 nd->nd_repstat = NFSERR_TOOSMALL;
5910 if (nd->nd_repstat == 0)
5911 nd->nd_repstat = error;
5913 NFSEXITCODE2(0, nd);
5918 * nfsv4 service not supported
5921 nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram,
5922 __unused vnode_t vp, __unused struct nfsexstuff *exp)
5925 nd->nd_repstat = NFSERR_NOTSUPP;
5926 NFSEXITCODE2(0, nd);