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 * Rpc op calls, generally called from the vnode op calls or through the
41 * buffer cache, for NFS v2, 3 and 4.
42 * These do not normally make any changes to vnode arguments or use
43 * structures that might change between the VFS variants. The returned
44 * arguments are all at the end, after the NFSPROC_T *p one.
48 #include "opt_inet6.h"
50 #include <fs/nfs/nfsport.h>
51 #include <fs/nfsclient/nfs.h>
52 #include <sys/extattr.h>
53 #include <sys/sysctl.h>
54 #include <sys/taskqueue.h>
56 SYSCTL_DECL(_vfs_nfs);
58 static int nfsignore_eexist = 0;
59 SYSCTL_INT(_vfs_nfs, OID_AUTO, ignore_eexist, CTLFLAG_RW,
60 &nfsignore_eexist, 0, "NFS ignore EEXIST replies for mkdir/symlink");
62 static int nfscl_dssameconn = 0;
63 SYSCTL_INT(_vfs_nfs, OID_AUTO, dssameconn, CTLFLAG_RW,
64 &nfscl_dssameconn, 0, "Use same TCP connection to multiple DSs");
69 extern int nfs_numnfscbd;
70 extern struct timeval nfsboottime;
71 extern u_int32_t newnfs_false, newnfs_true;
72 extern nfstype nfsv34_type[9];
73 extern int nfsrv_useacl;
74 extern char nfsv4_callbackaddr[INET6_ADDRSTRLEN];
75 extern int nfscl_debuglevel;
76 extern int nfs_pnfsiothreads;
77 extern u_long sb_max_adj;
78 extern int nfs_maxcopyrange;
80 int nfstest_outofseq = 0;
81 int nfscl_assumeposixlocks = 1;
82 int nfscl_enablecallb = 0;
83 short nfsv4_cbport = NFSV4_CBPORT;
84 int nfstest_openallsetattr = 0;
85 #endif /* !APPLEKEXT */
87 #define DIRHDSIZ offsetof(struct dirent, d_name)
90 * nfscl_getsameserver() can return one of three values:
91 * NFSDSP_USETHISSESSION - Use this session for the DS.
92 * NFSDSP_SEQTHISSESSION - Use the nfsclds_sequence field of this dsp for new
94 * NFSDSP_NOTFOUND - No matching server was found.
97 NFSDSP_USETHISSESSION = 0,
98 NFSDSP_SEQTHISSESSION = 1,
103 * Do a write RPC on a DS data file, using this structure for the arguments,
104 * so that this function can be executed by a separate kernel process.
106 struct nfsclwritedsdorpc {
113 nfsv4stateid_t *stateidp;
129 static int nfsrpc_setattrrpc(vnode_t , struct vattr *, nfsv4stateid_t *,
130 struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, void *);
131 static int nfsrpc_readrpc(vnode_t , struct uio *, struct ucred *,
132 nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *, void *);
133 static int nfsrpc_writerpc(vnode_t , struct uio *, int *, int *,
134 struct ucred *, nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *,
136 static int nfsrpc_createv23(vnode_t , char *, int, struct vattr *,
137 nfsquad_t, int, struct ucred *, NFSPROC_T *, struct nfsvattr *,
138 struct nfsvattr *, struct nfsfh **, int *, int *, void *);
139 static int nfsrpc_createv4(vnode_t , char *, int, struct vattr *,
140 nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, struct ucred *,
141 NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, struct nfsfh **, int *,
142 int *, void *, int *);
143 static int nfsrpc_locku(struct nfsrv_descript *, struct nfsmount *,
144 struct nfscllockowner *, u_int64_t, u_int64_t,
145 u_int32_t, struct ucred *, NFSPROC_T *, int);
146 static int nfsrpc_setaclrpc(vnode_t, struct ucred *, NFSPROC_T *,
147 struct acl *, nfsv4stateid_t *, void *);
148 static int nfsrpc_getlayout(struct nfsmount *, vnode_t, struct nfsfh *, int,
149 uint32_t *, nfsv4stateid_t *, uint64_t, struct nfscllayout **,
150 struct ucred *, NFSPROC_T *);
151 static int nfsrpc_fillsa(struct nfsmount *, struct sockaddr_in *,
152 struct sockaddr_in6 *, sa_family_t, int, int, struct nfsclds **,
154 static void nfscl_initsessionslots(struct nfsclsession *);
155 static int nfscl_doflayoutio(vnode_t, struct uio *, int *, int *, int *,
156 nfsv4stateid_t *, int, struct nfscldevinfo *, struct nfscllayout *,
157 struct nfsclflayout *, uint64_t, uint64_t, int, struct ucred *,
159 static int nfscl_dofflayoutio(vnode_t, struct uio *, int *, int *, int *,
160 nfsv4stateid_t *, int, struct nfscldevinfo *, struct nfscllayout *,
161 struct nfsclflayout *, uint64_t, uint64_t, int, int, struct mbuf *,
162 struct nfsclwritedsdorpc *, struct ucred *, NFSPROC_T *);
163 static struct mbuf *nfsm_copym(struct mbuf *, int, int);
164 static int nfsrpc_readds(vnode_t, struct uio *, nfsv4stateid_t *, int *,
165 struct nfsclds *, uint64_t, int, struct nfsfh *, int, int, int,
166 struct ucred *, NFSPROC_T *);
167 static int nfsrpc_writeds(vnode_t, struct uio *, int *, int *,
168 nfsv4stateid_t *, struct nfsclds *, uint64_t, int,
169 struct nfsfh *, int, int, int, int, struct ucred *, NFSPROC_T *);
170 static int nfsio_writedsmir(vnode_t, int *, int *, nfsv4stateid_t *,
171 struct nfsclds *, uint64_t, int, struct nfsfh *, struct mbuf *, int, int,
172 struct nfsclwritedsdorpc *, struct ucred *, NFSPROC_T *);
173 static int nfsrpc_writedsmir(vnode_t, int *, int *, nfsv4stateid_t *,
174 struct nfsclds *, uint64_t, int, struct nfsfh *, struct mbuf *, int, int,
175 struct ucred *, NFSPROC_T *);
176 static enum nfsclds_state nfscl_getsameserver(struct nfsmount *,
177 struct nfsclds *, struct nfsclds **, uint32_t *);
178 static int nfsio_commitds(vnode_t, uint64_t, int, struct nfsclds *,
179 struct nfsfh *, int, int, struct nfsclwritedsdorpc *, struct ucred *,
181 static int nfsrpc_commitds(vnode_t, uint64_t, int, struct nfsclds *,
182 struct nfsfh *, int, int, struct ucred *, NFSPROC_T *);
184 static int nfsio_adviseds(vnode_t, uint64_t, int, int, struct nfsclds *,
185 struct nfsfh *, int, int, struct nfsclwritedsdorpc *, struct ucred *,
187 static int nfsrpc_adviseds(vnode_t, uint64_t, int, int, struct nfsclds *,
188 struct nfsfh *, int, int, struct ucred *, NFSPROC_T *);
190 static int nfsrpc_allocaterpc(vnode_t, off_t, off_t, nfsv4stateid_t *,
191 struct nfsvattr *, int *, struct ucred *, NFSPROC_T *, void *);
192 static void nfsrv_setuplayoutget(struct nfsrv_descript *, int, uint64_t,
193 uint64_t, uint64_t, nfsv4stateid_t *, int, int, int);
194 static int nfsrv_parseug(struct nfsrv_descript *, int, uid_t *, gid_t *,
196 static int nfsrv_parselayoutget(struct nfsmount *, struct nfsrv_descript *,
197 nfsv4stateid_t *, int *, struct nfsclflayouthead *);
198 static int nfsrpc_getopenlayout(struct nfsmount *, vnode_t, u_int8_t *,
199 int, uint8_t *, int, uint32_t, struct nfsclopen *, uint8_t *, int,
200 struct nfscldeleg **, struct ucred *, NFSPROC_T *);
201 static int nfsrpc_getcreatelayout(vnode_t, char *, int, struct vattr *,
202 nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **,
203 struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *,
204 struct nfsfh **, int *, int *, void *, int *);
205 static int nfsrpc_openlayoutrpc(struct nfsmount *, vnode_t, u_int8_t *,
206 int, uint8_t *, int, uint32_t, struct nfsclopen *, uint8_t *, int,
207 struct nfscldeleg **, nfsv4stateid_t *, int, int, int, int *,
208 struct nfsclflayouthead *, int *, struct ucred *, NFSPROC_T *);
209 static int nfsrpc_createlayout(vnode_t, char *, int, struct vattr *,
210 nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **,
211 struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *,
212 struct nfsfh **, int *, int *, void *, int *, nfsv4stateid_t *,
213 int, int, int, int *, struct nfsclflayouthead *, int *);
214 static int nfsrpc_layoutget(struct nfsmount *, uint8_t *, int, int, uint64_t,
215 uint64_t, uint64_t, int, int, nfsv4stateid_t *, int *,
216 struct nfsclflayouthead *, struct ucred *, NFSPROC_T *, void *);
217 static int nfsrpc_layoutgetres(struct nfsmount *, vnode_t, uint8_t *,
218 int, nfsv4stateid_t *, int, uint32_t *, struct nfscllayout **,
219 struct nfsclflayouthead *, int, int, int *, struct ucred *, NFSPROC_T *);
220 static int nfsrpc_copyrpc(vnode_t, off_t, vnode_t, off_t, size_t *,
221 nfsv4stateid_t *, nfsv4stateid_t *, struct nfsvattr *, int *,
222 struct nfsvattr *, int *, bool, int *, struct ucred *, NFSPROC_T *);
223 static int nfsrpc_seekrpc(vnode_t, off_t *, nfsv4stateid_t *, bool *,
224 int, struct nfsvattr *, int *, struct ucred *);
226 int nfs_pnfsio(task_fn_t *, void *);
229 * nfs null call from vfs.
232 nfsrpc_null(vnode_t vp, struct ucred *cred, NFSPROC_T *p)
235 struct nfsrv_descript nfsd, *nd = &nfsd;
237 NFSCL_REQSTART(nd, NFSPROC_NULL, vp);
238 error = nfscl_request(nd, vp, p, cred, NULL);
239 if (nd->nd_repstat && !error)
240 error = nd->nd_repstat;
241 mbuf_freem(nd->nd_mrep);
247 * For nfs version 3 and 4, use the access rpc to check accessibility. If file
248 * modes are changed on the server, accesses might still fail later.
251 nfsrpc_access(vnode_t vp, int acmode, struct ucred *cred,
252 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp)
255 u_int32_t mode, rmode;
258 mode = NFSACCESS_READ;
261 if (vnode_vtype(vp) == VDIR) {
263 mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND |
266 mode |= NFSACCESS_LOOKUP;
269 mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND);
271 mode |= NFSACCESS_EXECUTE;
275 * Now, just call nfsrpc_accessrpc() to do the actual RPC.
277 error = nfsrpc_accessrpc(vp, mode, cred, p, nap, attrflagp, &rmode,
281 * The NFS V3 spec does not clarify whether or not
282 * the returned access bits can be a superset of
283 * the ones requested, so...
285 if (!error && (rmode & mode) != mode)
291 * The actual rpc, separated out for Darwin.
294 nfsrpc_accessrpc(vnode_t vp, u_int32_t mode, struct ucred *cred,
295 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, u_int32_t *rmodep,
299 u_int32_t supported, rmode;
301 struct nfsrv_descript nfsd, *nd = &nfsd;
302 nfsattrbit_t attrbits;
306 NFSCL_REQSTART(nd, NFSPROC_ACCESS, vp);
307 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
308 *tl = txdr_unsigned(mode);
309 if (nd->nd_flag & ND_NFSV4) {
311 * And do a Getattr op.
313 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
314 *tl = txdr_unsigned(NFSV4OP_GETATTR);
315 NFSGETATTR_ATTRBIT(&attrbits);
316 (void) nfsrv_putattrbit(nd, &attrbits);
318 error = nfscl_request(nd, vp, p, cred, stuff);
321 if (nd->nd_flag & ND_NFSV3) {
322 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
326 if (!nd->nd_repstat) {
327 if (nd->nd_flag & ND_NFSV4) {
328 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
329 supported = fxdr_unsigned(u_int32_t, *tl++);
331 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
333 rmode = fxdr_unsigned(u_int32_t, *tl);
334 if (nd->nd_flag & ND_NFSV4)
335 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
338 * It's not obvious what should be done about
339 * unsupported access modes. For now, be paranoid
340 * and clear the unsupported ones.
345 error = nd->nd_repstat;
347 mbuf_freem(nd->nd_mrep);
355 nfsrpc_open(vnode_t vp, int amode, struct ucred *cred, NFSPROC_T *p)
357 struct nfsclopen *op;
358 struct nfscldeleg *dp;
360 struct nfsnode *np = VTONFS(vp);
361 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
362 u_int32_t mode, clidrev;
363 int ret, newone, error, expireret = 0, retrycnt;
366 * For NFSv4, Open Ops are only done on Regular Files.
368 if (vnode_vtype(vp) != VREG)
372 mode |= NFSV4OPEN_ACCESSREAD;
374 mode |= NFSV4OPEN_ACCESSWRITE;
379 { char name[100]; int namel;
380 namel = (np->n_v4->n4_namelen < 100) ? np->n_v4->n4_namelen : 99;
381 bcopy(NFS4NODENAME(np->n_v4), name, namel);
383 printf("rpcopen p=0x%x name=%s",p->p_pid,name);
384 if (nfhp->nfh_len > 0) printf(" fh=0x%x\n",nfhp->nfh_fh[12]);
385 else printf(" fhl=0\n");
390 error = nfscl_open(vp, nfhp->nfh_fh, nfhp->nfh_len, mode, 1,
391 cred, p, NULL, &op, &newone, &ret, 1);
395 if (nmp->nm_clp != NULL)
396 clidrev = nmp->nm_clp->nfsc_clientidrev;
399 if (ret == NFSCLOPEN_DOOPEN) {
400 if (np->n_v4 != NULL) {
402 * For the first attempt, try and get a layout, if
403 * pNFS is enabled for the mount.
405 if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 ||
406 nfs_numnfscbd == 0 ||
407 (np->n_flag & NNOLAYOUT) != 0 || retrycnt > 0)
408 error = nfsrpc_openrpc(nmp, vp,
410 np->n_v4->n4_fhlen, np->n_fhp->nfh_fh,
411 np->n_fhp->nfh_len, mode, op,
412 NFS4NODENAME(np->n_v4),
413 np->n_v4->n4_namelen,
414 &dp, 0, 0x0, cred, p, 0, 0);
416 error = nfsrpc_getopenlayout(nmp, vp,
418 np->n_v4->n4_fhlen, np->n_fhp->nfh_fh,
419 np->n_fhp->nfh_len, mode, op,
420 NFS4NODENAME(np->n_v4),
421 np->n_v4->n4_namelen, &dp, cred, p);
424 OSBitAndAtomic((int32_t)~NDELEGMOD, (UInt32 *)&np->n_flag);
427 np->n_flag &= ~NDELEGMOD;
429 * Invalidate the attribute cache, so that
430 * attributes that pre-date the issue of a
431 * delegation are not cached, since the
432 * cached attributes will remain valid while
433 * the delegation is held.
435 NFSINVALATTRCACHE(np);
438 (void) nfscl_deleg(nmp->nm_mountp,
439 op->nfso_own->nfsow_clp,
440 nfhp->nfh_fh, nfhp->nfh_len, cred, p, &dp);
445 newnfs_copyincred(cred, &op->nfso_cred);
446 } else if (ret == NFSCLOPEN_SETCRED)
448 * This is a new local open on a delegation. It needs
449 * to have credentials so that an open can be done
450 * against the server during recovery.
452 newnfs_copyincred(cred, &op->nfso_cred);
455 * nfso_opencnt is the count of how many VOP_OPEN()s have
456 * been done on this Open successfully and a VOP_CLOSE()
457 * is expected for each of these.
458 * If error is non-zero, don't increment it, since the Open
459 * hasn't succeeded yet.
463 nfscl_openrelease(nmp, op, error, newone);
464 if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
465 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
466 error == NFSERR_BADSESSION) {
467 (void) nfs_catnap(PZERO, error, "nfs_open");
468 } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID)
470 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
473 } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
474 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
475 error == NFSERR_BADSESSION ||
476 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
477 expireret == 0 && clidrev != 0 && retrycnt < 4));
478 if (error && retrycnt >= 4)
484 * the actual open rpc
487 nfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen,
488 u_int8_t *newfhp, int newfhlen, u_int32_t mode, struct nfsclopen *op,
489 u_int8_t *name, int namelen, struct nfscldeleg **dpp,
490 int reclaim, u_int32_t delegtype, struct ucred *cred, NFSPROC_T *p,
491 int syscred, int recursed)
494 struct nfsrv_descript nfsd, *nd = &nfsd;
495 struct nfscldeleg *dp, *ndp = NULL;
496 struct nfsvattr nfsva;
497 u_int32_t rflags, deleg;
498 nfsattrbit_t attrbits;
499 int error, ret, acesize, limitby;
500 struct nfsclsession *tsep;
504 nfscl_reqstart(nd, NFSPROC_OPEN, nmp, nfhp, fhlen, NULL, NULL, 0, 0);
505 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
506 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
507 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
508 *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
509 tsep = nfsmnt_mdssession(nmp);
510 *tl++ = tsep->nfsess_clientid.lval[0];
511 *tl = tsep->nfsess_clientid.lval[1];
512 (void) nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN);
513 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
514 *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE);
516 *tl = txdr_unsigned(NFSV4OPEN_CLAIMPREVIOUS);
517 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
518 *tl = txdr_unsigned(delegtype);
521 *tl = txdr_unsigned(NFSV4OPEN_CLAIMDELEGATECUR);
522 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
523 if (NFSHASNFSV4N(nmp))
526 *tl++ = dp->nfsdl_stateid.seqid;
527 *tl++ = dp->nfsdl_stateid.other[0];
528 *tl++ = dp->nfsdl_stateid.other[1];
529 *tl = dp->nfsdl_stateid.other[2];
531 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
533 (void) nfsm_strtom(nd, name, namelen);
535 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
536 *tl = txdr_unsigned(NFSV4OP_GETATTR);
537 NFSZERO_ATTRBIT(&attrbits);
538 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
539 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY);
540 (void) nfsrv_putattrbit(nd, &attrbits);
542 nd->nd_flag |= ND_USEGSSNAME;
543 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
544 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
547 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
548 if (!nd->nd_repstat) {
549 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
551 op->nfso_stateid.seqid = *tl++;
552 op->nfso_stateid.other[0] = *tl++;
553 op->nfso_stateid.other[1] = *tl++;
554 op->nfso_stateid.other[2] = *tl;
555 rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
556 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
559 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
560 deleg = fxdr_unsigned(u_int32_t, *tl);
561 if (deleg == NFSV4OPEN_DELEGATEREAD ||
562 deleg == NFSV4OPEN_DELEGATEWRITE) {
563 if (!(op->nfso_own->nfsow_clp->nfsc_flags &
564 NFSCLFLAGS_FIRSTDELEG))
565 op->nfso_own->nfsow_clp->nfsc_flags |=
566 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
568 sizeof (struct nfscldeleg) + newfhlen,
569 M_NFSCLDELEG, M_WAITOK);
570 LIST_INIT(&ndp->nfsdl_owner);
571 LIST_INIT(&ndp->nfsdl_lock);
572 ndp->nfsdl_clp = op->nfso_own->nfsow_clp;
573 ndp->nfsdl_fhlen = newfhlen;
574 NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen);
575 newnfs_copyincred(cred, &ndp->nfsdl_cred);
576 nfscl_lockinit(&ndp->nfsdl_rwlock);
577 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
579 ndp->nfsdl_stateid.seqid = *tl++;
580 ndp->nfsdl_stateid.other[0] = *tl++;
581 ndp->nfsdl_stateid.other[1] = *tl++;
582 ndp->nfsdl_stateid.other[2] = *tl++;
583 ret = fxdr_unsigned(int, *tl);
584 if (deleg == NFSV4OPEN_DELEGATEWRITE) {
585 ndp->nfsdl_flags = NFSCLDL_WRITE;
587 * Indicates how much the file can grow.
589 NFSM_DISSECT(tl, u_int32_t *,
591 limitby = fxdr_unsigned(int, *tl++);
593 case NFSV4OPEN_LIMITSIZE:
594 ndp->nfsdl_sizelimit = fxdr_hyper(tl);
596 case NFSV4OPEN_LIMITBLOCKS:
597 ndp->nfsdl_sizelimit =
598 fxdr_unsigned(u_int64_t, *tl++);
599 ndp->nfsdl_sizelimit *=
600 fxdr_unsigned(u_int64_t, *tl);
603 error = NFSERR_BADXDR;
607 ndp->nfsdl_flags = NFSCLDL_READ;
610 ndp->nfsdl_flags |= NFSCLDL_RECALL;
611 error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, &ret,
615 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
616 error = NFSERR_BADXDR;
619 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
620 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
621 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
622 NULL, NULL, NULL, p, cred);
626 ndp->nfsdl_change = nfsva.na_filerev;
627 ndp->nfsdl_modtime = nfsva.na_mtime;
628 ndp->nfsdl_flags |= NFSCLDL_MODTIMESET;
630 if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM)) {
632 ret = nfsrpc_openconfirm(vp, newfhp, newfhlen, op,
634 if (ret == NFSERR_DELAY)
635 (void) nfs_catnap(PZERO, ret, "nfs_open");
636 } while (ret == NFSERR_DELAY);
639 if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) ||
640 nfscl_assumeposixlocks)
641 op->nfso_posixlock = 1;
643 op->nfso_posixlock = 0;
646 * If the server is handing out delegations, but we didn't
647 * get one because an OpenConfirm was required, try the
648 * Open again, to get a delegation. This is a harmless no-op,
649 * from a server's point of view.
651 if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM) &&
652 (op->nfso_own->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG)
653 && !error && dp == NULL && ndp == NULL && !recursed) {
655 ret = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp,
656 newfhlen, mode, op, name, namelen, &ndp, 0, 0x0,
657 cred, p, syscred, 1);
658 if (ret == NFSERR_DELAY)
659 (void) nfs_catnap(PZERO, ret, "nfs_open2");
660 } while (ret == NFSERR_DELAY);
663 free(ndp, M_NFSCLDELEG);
666 if (ret == NFSERR_STALECLIENTID ||
667 ret == NFSERR_STALEDONTRECOVER ||
668 ret == NFSERR_BADSESSION)
673 if (nd->nd_repstat != 0 && error == 0)
674 error = nd->nd_repstat;
675 if (error == NFSERR_STALECLIENTID)
676 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
680 else if (ndp != NULL)
681 free(ndp, M_NFSCLDELEG);
682 mbuf_freem(nd->nd_mrep);
690 nfsrpc_opendowngrade(vnode_t vp, u_int32_t mode, struct nfsclopen *op,
691 struct ucred *cred, NFSPROC_T *p)
694 struct nfsrv_descript nfsd, *nd = &nfsd;
697 NFSCL_REQSTART(nd, NFSPROC_OPENDOWNGRADE, vp);
698 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
699 if (NFSHASNFSV4N(VFSTONFS(vnode_mount(vp))))
702 *tl++ = op->nfso_stateid.seqid;
703 *tl++ = op->nfso_stateid.other[0];
704 *tl++ = op->nfso_stateid.other[1];
705 *tl++ = op->nfso_stateid.other[2];
706 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
707 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
708 *tl = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
709 error = nfscl_request(nd, vp, p, cred, NULL);
712 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
713 if (!nd->nd_repstat) {
714 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
715 op->nfso_stateid.seqid = *tl++;
716 op->nfso_stateid.other[0] = *tl++;
717 op->nfso_stateid.other[1] = *tl++;
718 op->nfso_stateid.other[2] = *tl;
720 if (nd->nd_repstat && error == 0)
721 error = nd->nd_repstat;
722 if (error == NFSERR_STALESTATEID)
723 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
725 mbuf_freem(nd->nd_mrep);
730 * V4 Close operation.
733 nfsrpc_close(vnode_t vp, int doclose, NFSPROC_T *p)
735 struct nfsclclient *clp;
738 if (vnode_vtype(vp) != VREG)
741 error = nfscl_doclose(vp, &clp, p);
743 error = nfscl_getclose(vp, &clp);
747 nfscl_clientrelease(clp);
755 nfsrpc_doclose(struct nfsmount *nmp, struct nfsclopen *op, NFSPROC_T *p)
757 struct nfsrv_descript nfsd, *nd = &nfsd;
758 struct nfscllockowner *lp, *nlp;
759 struct nfscllock *lop, *nlop;
761 u_int64_t off = 0, len = 0;
762 u_int32_t type = NFSV4LOCKT_READ;
763 int error, do_unlock, trycnt;
765 tcred = newnfs_getcred();
766 newnfs_copycred(&op->nfso_cred, tcred);
768 * (Theoretically this could be done in the same
769 * compound as the close, but having multiple
770 * sequenced Ops in the same compound might be
771 * too scary for some servers.)
773 if (op->nfso_posixlock) {
776 type = NFSV4LOCKT_READ;
780 * Since this function is only called from VOP_INACTIVE(), no
781 * other thread will be manipulating this Open. As such, the
782 * lock lists are not being changed by other threads, so it should
783 * be safe to do this without locking.
785 LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) {
787 LIST_FOREACH_SAFE(lop, &lp->nfsl_lock, nfslo_list, nlop) {
788 if (op->nfso_posixlock == 0) {
789 off = lop->nfslo_first;
790 len = lop->nfslo_end - lop->nfslo_first;
791 if (lop->nfslo_type == F_WRLCK)
792 type = NFSV4LOCKT_WRITE;
794 type = NFSV4LOCKT_READ;
799 error = nfsrpc_locku(nd, nmp, lp, off,
800 len, type, tcred, p, 0);
801 if ((nd->nd_repstat == NFSERR_GRACE ||
802 nd->nd_repstat == NFSERR_DELAY) &&
804 (void) nfs_catnap(PZERO,
807 } while ((nd->nd_repstat == NFSERR_GRACE ||
808 nd->nd_repstat == NFSERR_DELAY) &&
809 error == 0 && trycnt++ < 5);
810 if (op->nfso_posixlock)
813 nfscl_freelock(lop, 0);
816 * Do a ReleaseLockOwner.
817 * The lock owner name nfsl_owner may be used by other opens for
818 * other files but the lock_owner4 name that nfsrpc_rellockown()
819 * puts on the wire has the file handle for this file appended
820 * to it, so it can be done now.
822 (void)nfsrpc_rellockown(nmp, lp, lp->nfsl_open->nfso_fh,
823 lp->nfsl_open->nfso_fhlen, tcred, p);
827 * There could be other Opens for different files on the same
828 * OpenOwner, so locking is required.
831 nfscl_lockexcl(&op->nfso_own->nfsow_rwlock, NFSCLSTATEMUTEXPTR);
834 error = nfscl_tryclose(op, tcred, nmp, p);
835 if (error == NFSERR_GRACE)
836 (void) nfs_catnap(PZERO, error, "nfs_close");
837 } while (error == NFSERR_GRACE);
839 nfscl_lockunlock(&op->nfso_own->nfsow_rwlock);
841 LIST_FOREACH_SAFE(lp, &op->nfso_lock, nfsl_list, nlp)
842 nfscl_freelockowner(lp, 0);
843 nfscl_freeopen(op, 0);
849 * The actual Close RPC.
852 nfsrpc_closerpc(struct nfsrv_descript *nd, struct nfsmount *nmp,
853 struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p,
859 nfscl_reqstart(nd, NFSPROC_CLOSE, nmp, op->nfso_fh,
860 op->nfso_fhlen, NULL, NULL, 0, 0);
861 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
862 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
863 if (NFSHASNFSV4N(nmp))
866 *tl++ = op->nfso_stateid.seqid;
867 *tl++ = op->nfso_stateid.other[0];
868 *tl++ = op->nfso_stateid.other[1];
869 *tl = op->nfso_stateid.other[2];
871 nd->nd_flag |= ND_USEGSSNAME;
872 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
873 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
876 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
877 if (nd->nd_repstat == 0)
878 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
879 error = nd->nd_repstat;
880 if (error == NFSERR_STALESTATEID)
881 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
883 mbuf_freem(nd->nd_mrep);
888 * V4 Open Confirm RPC.
891 nfsrpc_openconfirm(vnode_t vp, u_int8_t *nfhp, int fhlen,
892 struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p)
895 struct nfsrv_descript nfsd, *nd = &nfsd;
896 struct nfsmount *nmp;
899 nmp = VFSTONFS(vnode_mount(vp));
900 if (NFSHASNFSV4N(nmp))
901 return (0); /* No confirmation for NFSv4.1. */
902 nfscl_reqstart(nd, NFSPROC_OPENCONFIRM, nmp, nfhp, fhlen, NULL, NULL,
904 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
905 *tl++ = op->nfso_stateid.seqid;
906 *tl++ = op->nfso_stateid.other[0];
907 *tl++ = op->nfso_stateid.other[1];
908 *tl++ = op->nfso_stateid.other[2];
909 *tl = txdr_unsigned(op->nfso_own->nfsow_seqid);
910 error = nfscl_request(nd, vp, p, cred, NULL);
913 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
914 if (!nd->nd_repstat) {
915 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
916 op->nfso_stateid.seqid = *tl++;
917 op->nfso_stateid.other[0] = *tl++;
918 op->nfso_stateid.other[1] = *tl++;
919 op->nfso_stateid.other[2] = *tl;
921 error = nd->nd_repstat;
922 if (error == NFSERR_STALESTATEID)
923 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
925 mbuf_freem(nd->nd_mrep);
930 * Do the setclientid and setclientid confirm RPCs. Called from nfs_statfs()
931 * when a mount has just occurred and when the server replies NFSERR_EXPIRED.
934 nfsrpc_setclient(struct nfsmount *nmp, struct nfsclclient *clp, int reclaim,
935 struct ucred *cred, NFSPROC_T *p)
938 struct nfsrv_descript nfsd;
939 struct nfsrv_descript *nd = &nfsd;
940 nfsattrbit_t attrbits;
941 u_int8_t *cp = NULL, *cp2, addr[INET6_ADDRSTRLEN + 9];
943 int error, isinet6 = 0, callblen;
946 static u_int32_t rev = 0;
949 struct nfsclsession *tsep;
951 if (nfsboottime.tv_sec == 0)
952 NFSSETBOOTTIME(nfsboottime);
953 clp->nfsc_rev = rev++;
954 if (NFSHASNFSV4N(nmp)) {
956 * Either there was no previous session or the
957 * previous session has failed, so...
958 * do an ExchangeID followed by the CreateSession.
960 error = nfsrpc_exchangeid(nmp, clp, &nmp->nm_sockreq, 0,
961 NFSV4EXCH_USEPNFSMDS | NFSV4EXCH_USENONPNFS, &dsp, cred, p);
962 NFSCL_DEBUG(1, "aft exch=%d\n", error);
964 error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess,
965 &nmp->nm_sockreq, NULL,
966 dsp->nfsclds_sess.nfsess_sequenceid, 1, cred, p);
970 * The old sessions cannot be safely free'd
971 * here, since they may still be used by
975 if (TAILQ_FIRST(&nmp->nm_sess) != NULL)
976 tsep = NFSMNT_MDSSESSION(nmp);
977 TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp,
980 * Wake up RPCs waiting for a slot on the
981 * old session. These will then fail with
982 * NFSERR_BADSESSION and be retried with the
983 * new session by nfsv4_setsequence().
984 * Also wakeup() processes waiting for the
988 wakeup(&tsep->nfsess_slots);
989 wakeup(&nmp->nm_sess);
992 nfscl_freenfsclds(dsp);
993 NFSCL_DEBUG(1, "aft createsess=%d\n", error);
994 if (error == 0 && reclaim == 0) {
995 error = nfsrpc_reclaimcomplete(nmp, cred, p);
996 NFSCL_DEBUG(1, "aft reclaimcomp=%d\n", error);
997 if (error == NFSERR_COMPLETEALREADY ||
998 error == NFSERR_NOTSUPP)
999 /* Ignore this error. */
1006 * Allocate a single session structure for NFSv4.0, because some of
1007 * the fields are used by NFSv4.0 although it doesn't do a session.
1009 dsp = malloc(sizeof(struct nfsclds), M_NFSCLDS, M_WAITOK | M_ZERO);
1010 mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF);
1011 mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", NULL, MTX_DEF);
1013 TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp, nfsclds_list);
1014 tsep = NFSMNT_MDSSESSION(nmp);
1017 nfscl_reqstart(nd, NFSPROC_SETCLIENTID, nmp, NULL, 0, NULL, NULL, 0, 0);
1018 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1019 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
1020 *tl = txdr_unsigned(clp->nfsc_rev);
1021 (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen);
1024 * set up the callback address
1026 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1027 *tl = txdr_unsigned(NFS_CALLBCKPROG);
1028 callblen = strlen(nfsv4_callbackaddr);
1030 cp = nfscl_getmyip(nmp, &a6, &isinet6);
1031 if (nfscl_enablecallb && nfs_numnfscbd > 0 &&
1032 (callblen > 0 || cp != NULL)) {
1033 port = htons(nfsv4_cbport);
1034 cp2 = (u_int8_t *)&port;
1036 if ((callblen > 0 &&
1037 strchr(nfsv4_callbackaddr, ':')) || isinet6) {
1038 char ip6buf[INET6_ADDRSTRLEN], *ip6add;
1040 (void) nfsm_strtom(nd, "tcp6", 4);
1041 if (callblen == 0) {
1042 ip6_sprintf(ip6buf, (struct in6_addr *)cp);
1045 ip6add = nfsv4_callbackaddr;
1047 snprintf(addr, INET6_ADDRSTRLEN + 9, "%s.%d.%d",
1048 ip6add, cp2[0], cp2[1]);
1052 (void) nfsm_strtom(nd, "tcp", 3);
1054 snprintf(addr, INET6_ADDRSTRLEN + 9,
1055 "%d.%d.%d.%d.%d.%d", cp[0], cp[1],
1056 cp[2], cp[3], cp2[0], cp2[1]);
1058 snprintf(addr, INET6_ADDRSTRLEN + 9,
1059 "%s.%d.%d", nfsv4_callbackaddr,
1062 (void) nfsm_strtom(nd, addr, strlen(addr));
1064 (void) nfsm_strtom(nd, "tcp", 3);
1065 (void) nfsm_strtom(nd, "0.0.0.0.0.0", 11);
1067 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1068 *tl = txdr_unsigned(clp->nfsc_cbident);
1069 nd->nd_flag |= ND_USEGSSNAME;
1070 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
1071 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
1074 if (nd->nd_repstat == 0) {
1075 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1076 tsep->nfsess_clientid.lval[0] = *tl++;
1077 tsep->nfsess_clientid.lval[1] = *tl++;
1078 confirm.lval[0] = *tl++;
1079 confirm.lval[1] = *tl;
1080 mbuf_freem(nd->nd_mrep);
1086 nfscl_reqstart(nd, NFSPROC_SETCLIENTIDCFRM, nmp, NULL, 0, NULL,
1088 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1089 *tl++ = tsep->nfsess_clientid.lval[0];
1090 *tl++ = tsep->nfsess_clientid.lval[1];
1091 *tl++ = confirm.lval[0];
1092 *tl = confirm.lval[1];
1093 nd->nd_flag |= ND_USEGSSNAME;
1094 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p,
1095 cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
1098 mbuf_freem(nd->nd_mrep);
1100 if (nd->nd_repstat == 0) {
1101 nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, nmp->nm_fh,
1102 nmp->nm_fhsize, NULL, NULL, 0, 0);
1103 NFSZERO_ATTRBIT(&attrbits);
1104 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME);
1105 (void) nfsrv_putattrbit(nd, &attrbits);
1106 nd->nd_flag |= ND_USEGSSNAME;
1107 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p,
1108 cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
1111 if (nd->nd_repstat == 0) {
1112 error = nfsv4_loadattr(nd, NULL, NULL, NULL, NULL, 0, NULL,
1113 NULL, NULL, NULL, NULL, 0, NULL, &lease, NULL, p, cred);
1116 clp->nfsc_renew = NFSCL_RENEW(lease);
1117 clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew;
1118 clp->nfsc_clientidrev++;
1119 if (clp->nfsc_clientidrev == 0)
1120 clp->nfsc_clientidrev++;
1124 error = nd->nd_repstat;
1126 mbuf_freem(nd->nd_mrep);
1134 nfsrpc_getattr(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
1135 struct nfsvattr *nap, void *stuff)
1137 struct nfsrv_descript nfsd, *nd = &nfsd;
1139 nfsattrbit_t attrbits;
1141 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
1142 if (nd->nd_flag & ND_NFSV4) {
1143 NFSGETATTR_ATTRBIT(&attrbits);
1144 (void) nfsrv_putattrbit(nd, &attrbits);
1146 error = nfscl_request(nd, vp, p, cred, stuff);
1149 if (!nd->nd_repstat)
1150 error = nfsm_loadattr(nd, nap);
1152 error = nd->nd_repstat;
1153 mbuf_freem(nd->nd_mrep);
1158 * nfs getattr call with non-vnode arguemnts.
1161 nfsrpc_getattrnovp(struct nfsmount *nmp, u_int8_t *fhp, int fhlen, int syscred,
1162 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, u_int64_t *xidp,
1165 struct nfsrv_descript nfsd, *nd = &nfsd;
1166 int error, vers = NFS_VER2;
1167 nfsattrbit_t attrbits;
1169 nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, fhp, fhlen, NULL, NULL, 0, 0);
1170 if (nd->nd_flag & ND_NFSV4) {
1172 NFSGETATTR_ATTRBIT(&attrbits);
1173 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME);
1174 (void) nfsrv_putattrbit(nd, &attrbits);
1175 } else if (nd->nd_flag & ND_NFSV3) {
1179 nd->nd_flag |= ND_USEGSSNAME;
1180 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
1181 NFS_PROG, vers, NULL, 1, xidp, NULL);
1184 if (nd->nd_repstat == 0) {
1185 if ((nd->nd_flag & ND_NFSV4) != 0)
1186 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
1187 NULL, NULL, NULL, NULL, NULL, 0, NULL, leasep, NULL,
1190 error = nfsm_loadattr(nd, nap);
1192 error = nd->nd_repstat;
1193 mbuf_freem(nd->nd_mrep);
1198 * Do an nfs setattr operation.
1201 nfsrpc_setattr(vnode_t vp, struct vattr *vap, NFSACL_T *aclp,
1202 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *rnap, int *attrflagp,
1205 int error, expireret = 0, openerr, retrycnt;
1206 u_int32_t clidrev = 0, mode;
1207 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1209 nfsv4stateid_t stateid;
1212 if (nmp->nm_clp != NULL)
1213 clidrev = nmp->nm_clp->nfsc_clientidrev;
1214 if (vap != NULL && NFSATTRISSET(u_quad_t, vap, va_size))
1215 mode = NFSV4OPEN_ACCESSWRITE;
1217 mode = NFSV4OPEN_ACCESSREAD;
1222 if (NFSHASNFSV4(nmp)) {
1223 nfhp = VTONFS(vp)->n_fhp;
1224 error = nfscl_getstateid(vp, nfhp->nfh_fh,
1225 nfhp->nfh_len, mode, 0, cred, p, &stateid, &lckp);
1226 if (error && vnode_vtype(vp) == VREG &&
1227 (mode == NFSV4OPEN_ACCESSWRITE ||
1228 nfstest_openallsetattr)) {
1230 * No Open stateid, so try and open the file
1233 if (mode == NFSV4OPEN_ACCESSWRITE)
1234 openerr = nfsrpc_open(vp, FWRITE, cred,
1237 openerr = nfsrpc_open(vp, FREAD, cred,
1240 (void) nfscl_getstateid(vp,
1241 nfhp->nfh_fh, nfhp->nfh_len,
1242 mode, 0, cred, p, &stateid, &lckp);
1246 error = nfsrpc_setattrrpc(vp, vap, &stateid, cred, p,
1247 rnap, attrflagp, stuff);
1249 error = nfsrpc_setaclrpc(vp, cred, p, aclp, &stateid,
1251 if (error == NFSERR_OPENMODE && mode == NFSV4OPEN_ACCESSREAD) {
1253 nmp->nm_state |= NFSSTA_OPENMODE;
1256 if (error == NFSERR_STALESTATEID)
1257 nfscl_initiate_recovery(nmp->nm_clp);
1259 nfscl_lockderef(lckp);
1261 (void) nfsrpc_close(vp, 0, p);
1262 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1263 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1264 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
1265 (void) nfs_catnap(PZERO, error, "nfs_setattr");
1266 } else if ((error == NFSERR_EXPIRED ||
1267 error == NFSERR_BADSTATEID) && clidrev != 0) {
1268 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1271 } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1272 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1273 error == NFSERR_BADSESSION ||
1274 (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
1275 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1276 expireret == 0 && clidrev != 0 && retrycnt < 4) ||
1277 (error == NFSERR_OPENMODE && mode == NFSV4OPEN_ACCESSREAD &&
1279 if (error && retrycnt >= 4)
1285 nfsrpc_setattrrpc(vnode_t vp, struct vattr *vap,
1286 nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p,
1287 struct nfsvattr *rnap, int *attrflagp, void *stuff)
1290 struct nfsrv_descript nfsd, *nd = &nfsd;
1292 nfsattrbit_t attrbits;
1295 NFSCL_REQSTART(nd, NFSPROC_SETATTR, vp);
1296 if (nd->nd_flag & ND_NFSV4)
1297 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
1298 vap->va_type = vnode_vtype(vp);
1299 nfscl_fillsattr(nd, vap, vp, NFSSATTR_FULL, 0);
1300 if (nd->nd_flag & ND_NFSV3) {
1301 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1303 } else if (nd->nd_flag & ND_NFSV4) {
1304 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1305 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1306 NFSGETATTR_ATTRBIT(&attrbits);
1307 (void) nfsrv_putattrbit(nd, &attrbits);
1309 error = nfscl_request(nd, vp, p, cred, stuff);
1312 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
1313 error = nfscl_wcc_data(nd, vp, rnap, attrflagp, NULL, stuff);
1314 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 && !error)
1315 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1316 if (!(nd->nd_flag & ND_NFSV3) && !nd->nd_repstat && !error)
1317 error = nfscl_postop_attr(nd, rnap, attrflagp, stuff);
1318 mbuf_freem(nd->nd_mrep);
1319 if (nd->nd_repstat && !error)
1320 error = nd->nd_repstat;
1328 nfsrpc_lookup(vnode_t dvp, char *name, int len, struct ucred *cred,
1329 NFSPROC_T *p, struct nfsvattr *dnap, struct nfsvattr *nap,
1330 struct nfsfh **nfhpp, int *attrflagp, int *dattrflagp, void *stuff)
1333 struct nfsrv_descript nfsd, *nd = &nfsd;
1334 struct nfsmount *nmp;
1337 nfsattrbit_t attrbits;
1338 int error = 0, lookupp = 0;
1342 if (vnode_vtype(dvp) != VDIR)
1344 nmp = VFSTONFS(vnode_mount(dvp));
1345 if (len > NFS_MAXNAMLEN)
1346 return (ENAMETOOLONG);
1347 if (NFSHASNFSV4(nmp) && len == 1 &&
1350 * Just return the current dir's fh.
1353 nfhp = malloc(sizeof (struct nfsfh) +
1354 np->n_fhp->nfh_len, M_NFSFH, M_WAITOK);
1355 nfhp->nfh_len = np->n_fhp->nfh_len;
1356 NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len);
1360 if (NFSHASNFSV4(nmp) && len == 2 &&
1361 name[0] == '.' && name[1] == '.') {
1363 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, dvp);
1365 NFSCL_REQSTART(nd, NFSPROC_LOOKUP, dvp);
1366 (void) nfsm_strtom(nd, name, len);
1368 if (nd->nd_flag & ND_NFSV4) {
1369 NFSGETATTR_ATTRBIT(&attrbits);
1370 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1371 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
1372 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1373 (void) nfsrv_putattrbit(nd, &attrbits);
1375 error = nfscl_request(nd, dvp, p, cred, stuff);
1378 if (nd->nd_repstat) {
1380 * When an NFSv4 Lookupp returns ENOENT, it means that
1381 * the lookup is at the root of an fs, so return this dir.
1383 if (nd->nd_repstat == NFSERR_NOENT && lookupp) {
1385 nfhp = malloc(sizeof (struct nfsfh) +
1386 np->n_fhp->nfh_len, M_NFSFH, M_WAITOK);
1387 nfhp->nfh_len = np->n_fhp->nfh_len;
1388 NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len);
1390 mbuf_freem(nd->nd_mrep);
1393 if (nd->nd_flag & ND_NFSV3)
1394 error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff);
1395 else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
1397 /* Load the directory attributes. */
1398 error = nfsm_loadattr(nd, dnap);
1404 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
1405 /* Load the directory attributes. */
1406 error = nfsm_loadattr(nd, dnap);
1410 /* Skip over the Lookup and GetFH operation status values. */
1411 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1413 error = nfsm_getfh(nd, nfhpp);
1417 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
1418 if ((nd->nd_flag & ND_NFSV3) && !error)
1419 error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff);
1421 mbuf_freem(nd->nd_mrep);
1422 if (!error && nd->nd_repstat)
1423 error = nd->nd_repstat;
1428 * Do a readlink rpc.
1431 nfsrpc_readlink(vnode_t vp, struct uio *uiop, struct ucred *cred,
1432 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
1435 struct nfsrv_descript nfsd, *nd = &nfsd;
1436 struct nfsnode *np = VTONFS(vp);
1437 nfsattrbit_t attrbits;
1438 int error, len, cangetattr = 1;
1441 NFSCL_REQSTART(nd, NFSPROC_READLINK, vp);
1442 if (nd->nd_flag & ND_NFSV4) {
1444 * And do a Getattr op.
1446 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1447 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1448 NFSGETATTR_ATTRBIT(&attrbits);
1449 (void) nfsrv_putattrbit(nd, &attrbits);
1451 error = nfscl_request(nd, vp, p, cred, stuff);
1454 if (nd->nd_flag & ND_NFSV3)
1455 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
1456 if (!nd->nd_repstat && !error) {
1457 NFSM_STRSIZ(len, NFS_MAXPATHLEN);
1459 * This seems weird to me, but must have been added to
1460 * FreeBSD for some reason. The only thing I can think of
1461 * is that there was/is some server that replies with
1462 * more link data than it should?
1464 if (len == NFS_MAXPATHLEN) {
1466 if (np->n_size > 0 && np->n_size < NFS_MAXPATHLEN) {
1472 error = nfsm_mbufuio(nd, uiop, len);
1473 if ((nd->nd_flag & ND_NFSV4) && !error && cangetattr)
1474 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
1476 if (nd->nd_repstat && !error)
1477 error = nd->nd_repstat;
1479 mbuf_freem(nd->nd_mrep);
1487 nfsrpc_read(vnode_t vp, struct uio *uiop, struct ucred *cred,
1488 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
1490 int error, expireret = 0, retrycnt;
1491 u_int32_t clidrev = 0;
1492 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1493 struct nfsnode *np = VTONFS(vp);
1494 struct ucred *newcred;
1495 struct nfsfh *nfhp = NULL;
1496 nfsv4stateid_t stateid;
1499 if (nmp->nm_clp != NULL)
1500 clidrev = nmp->nm_clp->nfsc_clientidrev;
1502 if (NFSHASNFSV4(nmp)) {
1504 newcred = NFSNEWCRED(cred);
1509 if (NFSHASNFSV4(nmp))
1510 (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
1511 NFSV4OPEN_ACCESSREAD, 0, newcred, p, &stateid,
1513 error = nfsrpc_readrpc(vp, uiop, newcred, &stateid, p, nap,
1515 if (error == NFSERR_OPENMODE) {
1517 nmp->nm_state |= NFSSTA_OPENMODE;
1520 if (error == NFSERR_STALESTATEID)
1521 nfscl_initiate_recovery(nmp->nm_clp);
1523 nfscl_lockderef(lckp);
1524 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1525 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1526 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
1527 (void) nfs_catnap(PZERO, error, "nfs_read");
1528 } else if ((error == NFSERR_EXPIRED ||
1529 error == NFSERR_BADSTATEID) && clidrev != 0) {
1530 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1533 } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1534 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1535 error == NFSERR_BADSESSION ||
1536 (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
1537 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1538 expireret == 0 && clidrev != 0 && retrycnt < 4) ||
1539 (error == NFSERR_OPENMODE && retrycnt < 4));
1540 if (error && retrycnt >= 4)
1542 if (NFSHASNFSV4(nmp))
1543 NFSFREECRED(newcred);
1548 * The actual read RPC.
1551 nfsrpc_readrpc(vnode_t vp, struct uio *uiop, struct ucred *cred,
1552 nfsv4stateid_t *stateidp, NFSPROC_T *p, struct nfsvattr *nap,
1553 int *attrflagp, void *stuff)
1556 int error = 0, len, retlen, tsiz, eof = 0;
1557 struct nfsrv_descript nfsd;
1558 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1559 struct nfsrv_descript *nd = &nfsd;
1564 tsiz = uio_uio_resid(uiop);
1565 tmp_off = uiop->uio_offset + tsiz;
1567 if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) {
1571 rsize = nmp->nm_rsize;
1576 len = (tsiz > rsize) ? rsize : tsiz;
1577 NFSCL_REQSTART(nd, NFSPROC_READ, vp);
1578 if (nd->nd_flag & ND_NFSV4)
1579 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
1580 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED * 3);
1581 if (nd->nd_flag & ND_NFSV2) {
1582 *tl++ = txdr_unsigned(uiop->uio_offset);
1583 *tl++ = txdr_unsigned(len);
1586 txdr_hyper(uiop->uio_offset, tl);
1587 *(tl + 2) = txdr_unsigned(len);
1590 * Since I can't do a Getattr for NFSv4 for Write, there
1591 * doesn't seem any point in doing one here, either.
1592 * (See the comment in nfsrpc_writerpc() for more info.)
1594 error = nfscl_request(nd, vp, p, cred, stuff);
1597 if (nd->nd_flag & ND_NFSV3) {
1598 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
1599 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
1600 error = nfsm_loadattr(nd, nap);
1604 if (nd->nd_repstat || error) {
1606 error = nd->nd_repstat;
1609 if (nd->nd_flag & ND_NFSV3) {
1610 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1611 eof = fxdr_unsigned(int, *(tl + 1));
1612 } else if (nd->nd_flag & ND_NFSV4) {
1613 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1614 eof = fxdr_unsigned(int, *tl);
1616 NFSM_STRSIZ(retlen, len);
1617 error = nfsm_mbufuio(nd, uiop, retlen);
1620 mbuf_freem(nd->nd_mrep);
1623 if (!(nd->nd_flag & ND_NFSV2)) {
1624 if (eof || retlen == 0)
1626 } else if (retlen < len)
1631 if (nd->nd_mrep != NULL)
1632 mbuf_freem(nd->nd_mrep);
1637 * nfs write operation
1638 * When called_from_strategy != 0, it should return EIO for an error that
1639 * indicates recovery is in progress, so that the buffer will be left
1640 * dirty and be written back to the server later. If it loops around,
1641 * the recovery thread could get stuck waiting for the buffer and recovery
1642 * will then deadlock.
1645 nfsrpc_write(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
1646 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
1647 void *stuff, int called_from_strategy)
1649 int error, expireret = 0, retrycnt, nostateid;
1650 u_int32_t clidrev = 0;
1651 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1652 struct nfsnode *np = VTONFS(vp);
1653 struct ucred *newcred;
1654 struct nfsfh *nfhp = NULL;
1655 nfsv4stateid_t stateid;
1659 if (nmp->nm_clp != NULL)
1660 clidrev = nmp->nm_clp->nfsc_clientidrev;
1662 if (NFSHASNFSV4(nmp)) {
1663 newcred = NFSNEWCRED(cred);
1670 if (NFSHASNFSV4(nmp)) {
1671 (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
1672 NFSV4OPEN_ACCESSWRITE, 0, newcred, p, &stateid,
1674 if (stateid.other[0] == 0 && stateid.other[1] == 0 &&
1675 stateid.other[2] == 0) {
1677 NFSCL_DEBUG(1, "stateid0 in write\n");
1682 * If there is no stateid for NFSv4, it means this is an
1683 * extraneous write after close. Basically a poorly
1684 * implemented buffer cache. Just don't do the write.
1689 error = nfsrpc_writerpc(vp, uiop, iomode, must_commit,
1690 newcred, &stateid, p, nap, attrflagp, stuff);
1691 if (error == NFSERR_STALESTATEID)
1692 nfscl_initiate_recovery(nmp->nm_clp);
1694 nfscl_lockderef(lckp);
1695 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1696 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1697 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
1698 (void) nfs_catnap(PZERO, error, "nfs_write");
1699 } else if ((error == NFSERR_EXPIRED ||
1700 error == NFSERR_BADSTATEID) && clidrev != 0) {
1701 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1704 } while (error == NFSERR_GRACE || error == NFSERR_DELAY ||
1705 ((error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION ||
1706 error == NFSERR_STALEDONTRECOVER) && called_from_strategy == 0) ||
1707 (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
1708 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1709 expireret == 0 && clidrev != 0 && retrycnt < 4));
1710 if (error != 0 && (retrycnt >= 4 ||
1711 ((error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION ||
1712 error == NFSERR_STALEDONTRECOVER) && called_from_strategy != 0)))
1714 if (NFSHASNFSV4(nmp))
1715 NFSFREECRED(newcred);
1720 * The actual write RPC.
1723 nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode,
1724 int *must_commit, struct ucred *cred, nfsv4stateid_t *stateidp,
1725 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
1728 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1729 struct nfsnode *np = VTONFS(vp);
1730 int error = 0, len, tsiz, rlen, commit, committed = NFSWRITE_FILESYNC;
1731 int wccflag = 0, wsize;
1733 struct nfsrv_descript nfsd;
1734 struct nfsrv_descript *nd = &nfsd;
1735 nfsattrbit_t attrbits;
1738 KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1"));
1740 tsiz = uio_uio_resid(uiop);
1741 tmp_off = uiop->uio_offset + tsiz;
1743 if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) {
1747 wsize = nmp->nm_wsize;
1749 nd->nd_mrep = NULL; /* NFSv2 sometimes does a write with */
1750 nd->nd_repstat = 0; /* uio_resid == 0, so the while is not done */
1753 len = (tsiz > wsize) ? wsize : tsiz;
1754 NFSCL_REQSTART(nd, NFSPROC_WRITE, vp);
1755 if (nd->nd_flag & ND_NFSV4) {
1756 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
1757 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+2*NFSX_UNSIGNED);
1758 txdr_hyper(uiop->uio_offset, tl);
1760 *tl++ = txdr_unsigned(*iomode);
1761 *tl = txdr_unsigned(len);
1762 } else if (nd->nd_flag & ND_NFSV3) {
1763 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+3*NFSX_UNSIGNED);
1764 txdr_hyper(uiop->uio_offset, tl);
1766 *tl++ = txdr_unsigned(len);
1767 *tl++ = txdr_unsigned(*iomode);
1768 *tl = txdr_unsigned(len);
1772 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1774 * Not sure why someone changed this, since the
1775 * RFC clearly states that "beginoffset" and
1776 * "totalcount" are ignored, but it wouldn't
1777 * surprise me if there's a busted server out there.
1779 /* Set both "begin" and "current" to non-garbage. */
1780 x = txdr_unsigned((u_int32_t)uiop->uio_offset);
1781 *tl++ = x; /* "begin offset" */
1782 *tl++ = x; /* "current offset" */
1783 x = txdr_unsigned(len);
1784 *tl++ = x; /* total to this offset */
1785 *tl = x; /* size of this write */
1788 nfsm_uiombuf(nd, uiop, len);
1790 * Although it is tempting to do a normal Getattr Op in the
1791 * NFSv4 compound, the result can be a nearly hung client
1792 * system if the Getattr asks for Owner and/or OwnerGroup.
1793 * It occurs when the client can't map either the Owner or
1794 * Owner_group name in the Getattr reply to a uid/gid. When
1795 * there is a cache miss, the kernel does an upcall to the
1796 * nfsuserd. Then, it can try and read the local /etc/passwd
1797 * or /etc/group file. It can then block in getnewbuf(),
1798 * waiting for dirty writes to be pushed to the NFS server.
1799 * The only reason this doesn't result in a complete
1800 * deadlock, is that the upcall times out and allows
1801 * the write to complete. However, progress is so slow
1802 * that it might just as well be deadlocked.
1803 * As such, we get the rest of the attributes, but not
1804 * Owner or Owner_group.
1805 * nb: nfscl_loadattrcache() needs to be told that these
1806 * partial attributes from a write rpc are being
1807 * passed in, via a argument flag.
1809 if (nd->nd_flag & ND_NFSV4) {
1810 NFSWRITEGETATTR_ATTRBIT(&attrbits);
1811 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1812 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1813 (void) nfsrv_putattrbit(nd, &attrbits);
1815 error = nfscl_request(nd, vp, p, cred, stuff);
1818 if (nd->nd_repstat) {
1820 * In case the rpc gets retried, roll
1821 * the uio fileds changed by nfsm_uiombuf()
1824 uiop->uio_offset -= len;
1825 uio_uio_resid_add(uiop, len);
1826 uio_iov_base_add(uiop, -len);
1827 uio_iov_len_add(uiop, len);
1829 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1830 error = nfscl_wcc_data(nd, vp, nap, attrflagp,
1835 if (!nd->nd_repstat) {
1836 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1837 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED
1839 rlen = fxdr_unsigned(int, *tl++);
1843 } else if (rlen < len) {
1844 backup = len - rlen;
1845 uio_iov_base_add(uiop, -(backup));
1846 uio_iov_len_add(uiop, backup);
1847 uiop->uio_offset -= backup;
1848 uio_uio_resid_add(uiop, backup);
1851 commit = fxdr_unsigned(int, *tl++);
1854 * Return the lowest commitment level
1855 * obtained by any of the RPCs.
1857 if (committed == NFSWRITE_FILESYNC)
1859 else if (committed == NFSWRITE_DATASYNC &&
1860 commit == NFSWRITE_UNSTABLE)
1863 if (!NFSHASWRITEVERF(nmp)) {
1864 NFSBCOPY((caddr_t)tl,
1865 (caddr_t)&nmp->nm_verf[0],
1867 NFSSETWRITEVERF(nmp);
1868 } else if (NFSBCMP(tl, nmp->nm_verf,
1871 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
1875 if (nd->nd_flag & ND_NFSV4)
1876 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1877 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV4)) {
1878 error = nfsm_loadattr(nd, nap);
1880 *attrflagp = NFS_LATTR_NOSHRINK;
1883 error = nd->nd_repstat;
1887 NFSWRITERPC_SETTIME(wccflag, np, nap, (nd->nd_flag & ND_NFSV4));
1888 mbuf_freem(nd->nd_mrep);
1893 if (nd->nd_mrep != NULL)
1894 mbuf_freem(nd->nd_mrep);
1895 *iomode = committed;
1896 if (nd->nd_repstat && !error)
1897 error = nd->nd_repstat;
1903 * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the
1904 * mode set to specify the file type and the size field for rdev.
1907 nfsrpc_mknod(vnode_t dvp, char *name, int namelen, struct vattr *vap,
1908 u_int32_t rdev, enum vtype vtyp, struct ucred *cred, NFSPROC_T *p,
1909 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
1910 int *attrflagp, int *dattrflagp, void *dstuff)
1914 struct nfsrv_descript nfsd, *nd = &nfsd;
1915 nfsattrbit_t attrbits;
1920 if (namelen > NFS_MAXNAMLEN)
1921 return (ENAMETOOLONG);
1922 NFSCL_REQSTART(nd, NFSPROC_MKNOD, dvp);
1923 if (nd->nd_flag & ND_NFSV4) {
1924 if (vtyp == VBLK || vtyp == VCHR) {
1925 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1926 *tl++ = vtonfsv34_type(vtyp);
1927 *tl++ = txdr_unsigned(NFSMAJOR(rdev));
1928 *tl = txdr_unsigned(NFSMINOR(rdev));
1930 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1931 *tl = vtonfsv34_type(vtyp);
1934 (void) nfsm_strtom(nd, name, namelen);
1935 if (nd->nd_flag & ND_NFSV3) {
1936 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1937 *tl = vtonfsv34_type(vtyp);
1939 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
1940 nfscl_fillsattr(nd, vap, dvp, 0, 0);
1941 if ((nd->nd_flag & ND_NFSV3) &&
1942 (vtyp == VCHR || vtyp == VBLK)) {
1943 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1944 *tl++ = txdr_unsigned(NFSMAJOR(rdev));
1945 *tl = txdr_unsigned(NFSMINOR(rdev));
1947 if (nd->nd_flag & ND_NFSV4) {
1948 NFSGETATTR_ATTRBIT(&attrbits);
1949 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1950 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
1951 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1952 (void) nfsrv_putattrbit(nd, &attrbits);
1954 if (nd->nd_flag & ND_NFSV2)
1955 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZERDEV, rdev);
1956 error = nfscl_request(nd, dvp, p, cred, dstuff);
1959 if (nd->nd_flag & ND_NFSV4)
1960 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
1961 if (!nd->nd_repstat) {
1962 if (nd->nd_flag & ND_NFSV4) {
1963 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1964 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1968 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
1972 if (nd->nd_flag & ND_NFSV3)
1973 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
1974 if (!error && nd->nd_repstat)
1975 error = nd->nd_repstat;
1977 mbuf_freem(nd->nd_mrep);
1982 * nfs file create call
1983 * Mostly just call the approriate routine. (I separated out v4, so that
1984 * error recovery wouldn't be as difficult.)
1987 nfsrpc_create(vnode_t dvp, char *name, int namelen, struct vattr *vap,
1988 nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p,
1989 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
1990 int *attrflagp, int *dattrflagp, void *dstuff)
1992 int error = 0, newone, expireret = 0, retrycnt, unlocked;
1993 struct nfsclowner *owp;
1994 struct nfscldeleg *dp;
1995 struct nfsmount *nmp = VFSTONFS(vnode_mount(dvp));
1998 if (NFSHASNFSV4(nmp)) {
2002 error = nfscl_open(dvp, NULL, 0, (NFSV4OPEN_ACCESSWRITE |
2003 NFSV4OPEN_ACCESSREAD), 0, cred, p, &owp, NULL, &newone,
2007 if (nmp->nm_clp != NULL)
2008 clidrev = nmp->nm_clp->nfsc_clientidrev;
2011 if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 ||
2012 nfs_numnfscbd == 0 || retrycnt > 0)
2013 error = nfsrpc_createv4(dvp, name, namelen, vap, cverf,
2014 fmode, owp, &dp, cred, p, dnap, nnap, nfhpp,
2015 attrflagp, dattrflagp, dstuff, &unlocked);
2017 error = nfsrpc_getcreatelayout(dvp, name, namelen, vap,
2018 cverf, fmode, owp, &dp, cred, p, dnap, nnap, nfhpp,
2019 attrflagp, dattrflagp, dstuff, &unlocked);
2021 * There is no need to invalidate cached attributes here,
2022 * since new post-delegation issue attributes are always
2023 * returned by nfsrpc_createv4() and these will update the
2027 (void) nfscl_deleg(nmp->nm_mountp, owp->nfsow_clp,
2028 (*nfhpp)->nfh_fh, (*nfhpp)->nfh_len, cred, p, &dp);
2029 nfscl_ownerrelease(nmp, owp, error, newone, unlocked);
2030 if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
2031 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
2032 error == NFSERR_BADSESSION) {
2033 (void) nfs_catnap(PZERO, error, "nfs_open");
2034 } else if ((error == NFSERR_EXPIRED ||
2035 error == NFSERR_BADSTATEID) && clidrev != 0) {
2036 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
2039 } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
2040 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
2041 error == NFSERR_BADSESSION ||
2042 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
2043 expireret == 0 && clidrev != 0 && retrycnt < 4));
2044 if (error && retrycnt >= 4)
2047 error = nfsrpc_createv23(dvp, name, namelen, vap, cverf,
2048 fmode, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp,
2055 * The create rpc for v2 and 3.
2058 nfsrpc_createv23(vnode_t dvp, char *name, int namelen, struct vattr *vap,
2059 nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p,
2060 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
2061 int *attrflagp, int *dattrflagp, void *dstuff)
2065 struct nfsrv_descript nfsd, *nd = &nfsd;
2070 if (namelen > NFS_MAXNAMLEN)
2071 return (ENAMETOOLONG);
2072 NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp);
2073 (void) nfsm_strtom(nd, name, namelen);
2074 if (nd->nd_flag & ND_NFSV3) {
2075 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2076 if (fmode & O_EXCL) {
2077 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE);
2078 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2079 *tl++ = cverf.lval[0];
2080 *tl = cverf.lval[1];
2082 *tl = txdr_unsigned(NFSCREATE_UNCHECKED);
2083 nfscl_fillsattr(nd, vap, dvp, 0, 0);
2086 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZE0, 0);
2088 error = nfscl_request(nd, dvp, p, cred, dstuff);
2091 if (nd->nd_repstat == 0) {
2092 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
2096 if (nd->nd_flag & ND_NFSV3)
2097 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2098 if (nd->nd_repstat != 0 && error == 0)
2099 error = nd->nd_repstat;
2101 mbuf_freem(nd->nd_mrep);
2106 nfsrpc_createv4(vnode_t dvp, char *name, int namelen, struct vattr *vap,
2107 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp,
2108 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
2109 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
2110 int *dattrflagp, void *dstuff, int *unlockedp)
2113 int error = 0, deleg, newone, ret, acesize, limitby;
2114 struct nfsrv_descript nfsd, *nd = &nfsd;
2115 struct nfsclopen *op;
2116 struct nfscldeleg *dp = NULL;
2119 nfsattrbit_t attrbits;
2120 nfsv4stateid_t stateid;
2122 struct nfsmount *nmp;
2123 struct nfsclsession *tsep;
2125 nmp = VFSTONFS(dvp->v_mount);
2132 if (namelen > NFS_MAXNAMLEN)
2133 return (ENAMETOOLONG);
2134 NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp);
2136 * For V4, this is actually an Open op.
2138 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2139 *tl++ = txdr_unsigned(owp->nfsow_seqid);
2140 *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
2141 NFSV4OPEN_ACCESSREAD);
2142 *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE);
2143 tsep = nfsmnt_mdssession(nmp);
2144 *tl++ = tsep->nfsess_clientid.lval[0];
2145 *tl = tsep->nfsess_clientid.lval[1];
2146 (void) nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN);
2147 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2148 *tl++ = txdr_unsigned(NFSV4OPEN_CREATE);
2149 if (fmode & O_EXCL) {
2150 if (NFSHASNFSV4N(nmp)) {
2151 if (NFSHASSESSPERSIST(nmp)) {
2152 /* Use GUARDED for persistent sessions. */
2153 *tl = txdr_unsigned(NFSCREATE_GUARDED);
2154 nfscl_fillsattr(nd, vap, dvp, 0, 0);
2156 /* Otherwise, use EXCLUSIVE4_1. */
2157 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41);
2158 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2159 *tl++ = cverf.lval[0];
2160 *tl = cverf.lval[1];
2161 nfscl_fillsattr(nd, vap, dvp, 0, 0);
2165 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE);
2166 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2167 *tl++ = cverf.lval[0];
2168 *tl = cverf.lval[1];
2171 *tl = txdr_unsigned(NFSCREATE_UNCHECKED);
2172 nfscl_fillsattr(nd, vap, dvp, 0, 0);
2174 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2175 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
2176 (void) nfsm_strtom(nd, name, namelen);
2177 /* Get the new file's handle and attributes. */
2178 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2179 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
2180 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2181 NFSGETATTR_ATTRBIT(&attrbits);
2182 (void) nfsrv_putattrbit(nd, &attrbits);
2183 /* Get the directory's post-op attributes. */
2184 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2185 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2186 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0);
2187 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2188 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2189 (void) nfsrv_putattrbit(nd, &attrbits);
2190 error = nfscl_request(nd, dvp, p, cred, dstuff);
2193 NFSCL_INCRSEQID(owp->nfsow_seqid, nd);
2194 if (nd->nd_repstat == 0) {
2195 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
2197 stateid.seqid = *tl++;
2198 stateid.other[0] = *tl++;
2199 stateid.other[1] = *tl++;
2200 stateid.other[2] = *tl;
2201 rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
2202 (void) nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
2203 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2204 deleg = fxdr_unsigned(int, *tl);
2205 if (deleg == NFSV4OPEN_DELEGATEREAD ||
2206 deleg == NFSV4OPEN_DELEGATEWRITE) {
2207 if (!(owp->nfsow_clp->nfsc_flags &
2208 NFSCLFLAGS_FIRSTDELEG))
2209 owp->nfsow_clp->nfsc_flags |=
2210 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
2212 sizeof (struct nfscldeleg) + NFSX_V4FHMAX,
2213 M_NFSCLDELEG, M_WAITOK);
2214 LIST_INIT(&dp->nfsdl_owner);
2215 LIST_INIT(&dp->nfsdl_lock);
2216 dp->nfsdl_clp = owp->nfsow_clp;
2217 newnfs_copyincred(cred, &dp->nfsdl_cred);
2218 nfscl_lockinit(&dp->nfsdl_rwlock);
2219 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
2221 dp->nfsdl_stateid.seqid = *tl++;
2222 dp->nfsdl_stateid.other[0] = *tl++;
2223 dp->nfsdl_stateid.other[1] = *tl++;
2224 dp->nfsdl_stateid.other[2] = *tl++;
2225 ret = fxdr_unsigned(int, *tl);
2226 if (deleg == NFSV4OPEN_DELEGATEWRITE) {
2227 dp->nfsdl_flags = NFSCLDL_WRITE;
2229 * Indicates how much the file can grow.
2231 NFSM_DISSECT(tl, u_int32_t *,
2233 limitby = fxdr_unsigned(int, *tl++);
2235 case NFSV4OPEN_LIMITSIZE:
2236 dp->nfsdl_sizelimit = fxdr_hyper(tl);
2238 case NFSV4OPEN_LIMITBLOCKS:
2239 dp->nfsdl_sizelimit =
2240 fxdr_unsigned(u_int64_t, *tl++);
2241 dp->nfsdl_sizelimit *=
2242 fxdr_unsigned(u_int64_t, *tl);
2245 error = NFSERR_BADXDR;
2249 dp->nfsdl_flags = NFSCLDL_READ;
2252 dp->nfsdl_flags |= NFSCLDL_RECALL;
2253 error = nfsrv_dissectace(nd, &dp->nfsdl_ace, &ret,
2257 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
2258 error = NFSERR_BADXDR;
2261 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
2264 /* Get rid of the PutFH and Getattr status values. */
2265 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
2266 /* Load the directory attributes. */
2267 error = nfsm_loadattr(nd, dnap);
2271 if (dp != NULL && *attrflagp) {
2272 dp->nfsdl_change = nnap->na_filerev;
2273 dp->nfsdl_modtime = nnap->na_mtime;
2274 dp->nfsdl_flags |= NFSCLDL_MODTIMESET;
2277 * We can now complete the Open state.
2281 dp->nfsdl_fhlen = nfhp->nfh_len;
2282 NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, nfhp->nfh_len);
2285 * Get an Open structure that will be
2286 * attached to the OpenOwner, acquired already.
2288 error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len,
2289 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0,
2290 cred, p, NULL, &op, &newone, NULL, 0);
2293 op->nfso_stateid = stateid;
2294 newnfs_copyincred(cred, &op->nfso_cred);
2295 if ((rflags & NFSV4OPEN_RESULTCONFIRM)) {
2297 ret = nfsrpc_openconfirm(dvp, nfhp->nfh_fh,
2298 nfhp->nfh_len, op, cred, p);
2299 if (ret == NFSERR_DELAY)
2300 (void) nfs_catnap(PZERO, ret, "nfs_create");
2301 } while (ret == NFSERR_DELAY);
2306 * If the server is handing out delegations, but we didn't
2307 * get one because an OpenConfirm was required, try the
2308 * Open again, to get a delegation. This is a harmless no-op,
2309 * from a server's point of view.
2311 if ((rflags & NFSV4OPEN_RESULTCONFIRM) &&
2312 (owp->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) &&
2313 !error && dp == NULL) {
2315 ret = nfsrpc_openrpc(VFSTONFS(vnode_mount(dvp)), dvp,
2316 np->n_fhp->nfh_fh, np->n_fhp->nfh_len,
2317 nfhp->nfh_fh, nfhp->nfh_len,
2318 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), op,
2319 name, namelen, &dp, 0, 0x0, cred, p, 0, 1);
2320 if (ret == NFSERR_DELAY)
2321 (void) nfs_catnap(PZERO, ret, "nfs_crt2");
2322 } while (ret == NFSERR_DELAY);
2325 free(dp, M_NFSCLDELEG);
2328 if (ret == NFSERR_STALECLIENTID ||
2329 ret == NFSERR_STALEDONTRECOVER ||
2330 ret == NFSERR_BADSESSION)
2334 nfscl_openrelease(nmp, op, error, newone);
2337 if (nd->nd_repstat != 0 && error == 0)
2338 error = nd->nd_repstat;
2339 if (error == NFSERR_STALECLIENTID)
2340 nfscl_initiate_recovery(owp->nfsow_clp);
2344 else if (dp != NULL)
2345 free(dp, M_NFSCLDELEG);
2346 mbuf_freem(nd->nd_mrep);
2354 nfsrpc_remove(vnode_t dvp, char *name, int namelen, vnode_t vp,
2355 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp,
2359 struct nfsrv_descript nfsd, *nd = &nfsd;
2361 struct nfsmount *nmp;
2362 nfsv4stateid_t dstateid;
2363 int error, ret = 0, i;
2366 if (namelen > NFS_MAXNAMLEN)
2367 return (ENAMETOOLONG);
2368 nmp = VFSTONFS(vnode_mount(dvp));
2370 if (NFSHASNFSV4(nmp) && ret == 0) {
2371 ret = nfscl_removedeleg(vp, p, &dstateid);
2373 NFSCL_REQSTART(nd, NFSPROC_RETDELEGREMOVE, vp);
2374 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID +
2376 if (NFSHASNFSV4N(nmp))
2379 *tl++ = dstateid.seqid;
2380 *tl++ = dstateid.other[0];
2381 *tl++ = dstateid.other[1];
2382 *tl++ = dstateid.other[2];
2383 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2385 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
2386 np->n_fhp->nfh_len, 0);
2387 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2388 *tl = txdr_unsigned(NFSV4OP_REMOVE);
2394 NFSCL_REQSTART(nd, NFSPROC_REMOVE, dvp);
2395 (void) nfsm_strtom(nd, name, namelen);
2396 error = nfscl_request(nd, dvp, p, cred, dstuff);
2399 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
2400 /* For NFSv4, parse out any Delereturn replies. */
2401 if (ret > 0 && nd->nd_repstat != 0 &&
2402 (nd->nd_flag & ND_NOMOREDATA)) {
2404 * If the Delegreturn failed, try again without
2405 * it. The server will Recall, as required.
2407 mbuf_freem(nd->nd_mrep);
2410 for (i = 0; i < (ret * 2); i++) {
2411 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
2413 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2415 nd->nd_flag |= ND_NOMOREDATA;
2418 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2420 if (nd->nd_repstat && !error)
2421 error = nd->nd_repstat;
2423 mbuf_freem(nd->nd_mrep);
2428 * Do an nfs rename rpc.
2431 nfsrpc_rename(vnode_t fdvp, vnode_t fvp, char *fnameptr, int fnamelen,
2432 vnode_t tdvp, vnode_t tvp, char *tnameptr, int tnamelen, struct ucred *cred,
2433 NFSPROC_T *p, struct nfsvattr *fnap, struct nfsvattr *tnap,
2434 int *fattrflagp, int *tattrflagp, void *fstuff, void *tstuff)
2437 struct nfsrv_descript nfsd, *nd = &nfsd;
2438 struct nfsmount *nmp;
2440 nfsattrbit_t attrbits;
2441 nfsv4stateid_t fdstateid, tdstateid;
2442 int error = 0, ret = 0, gottd = 0, gotfd = 0, i;
2446 nmp = VFSTONFS(vnode_mount(fdvp));
2447 if (fnamelen > NFS_MAXNAMLEN || tnamelen > NFS_MAXNAMLEN)
2448 return (ENAMETOOLONG);
2450 if (NFSHASNFSV4(nmp) && ret == 0) {
2451 ret = nfscl_renamedeleg(fvp, &fdstateid, &gotfd, tvp,
2452 &tdstateid, &gottd, p);
2453 if (gotfd && gottd) {
2454 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME2, fvp);
2456 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, fvp);
2458 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, tvp);
2461 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2462 if (NFSHASNFSV4N(nmp))
2465 *tl++ = fdstateid.seqid;
2466 *tl++ = fdstateid.other[0];
2467 *tl++ = fdstateid.other[1];
2468 *tl = fdstateid.other[2];
2470 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2471 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2473 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
2474 np->n_fhp->nfh_len, 0);
2475 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2476 *tl = txdr_unsigned(NFSV4OP_DELEGRETURN);
2480 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2481 if (NFSHASNFSV4N(nmp))
2484 *tl++ = tdstateid.seqid;
2485 *tl++ = tdstateid.other[0];
2486 *tl++ = tdstateid.other[1];
2487 *tl = tdstateid.other[2];
2490 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2491 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2493 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
2494 np->n_fhp->nfh_len, 0);
2495 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2496 *tl = txdr_unsigned(NFSV4OP_SAVEFH);
2502 NFSCL_REQSTART(nd, NFSPROC_RENAME, fdvp);
2503 if (nd->nd_flag & ND_NFSV4) {
2504 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2505 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2506 NFSWCCATTR_ATTRBIT(&attrbits);
2507 (void) nfsrv_putattrbit(nd, &attrbits);
2508 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2509 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2510 (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh,
2511 VTONFS(tdvp)->n_fhp->nfh_len, 0);
2512 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2513 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2514 (void) nfsrv_putattrbit(nd, &attrbits);
2515 nd->nd_flag |= ND_V4WCCATTR;
2516 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2517 *tl = txdr_unsigned(NFSV4OP_RENAME);
2519 (void) nfsm_strtom(nd, fnameptr, fnamelen);
2520 if (!(nd->nd_flag & ND_NFSV4))
2521 (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh,
2522 VTONFS(tdvp)->n_fhp->nfh_len, 0);
2523 (void) nfsm_strtom(nd, tnameptr, tnamelen);
2524 error = nfscl_request(nd, fdvp, p, cred, fstuff);
2527 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
2528 /* For NFSv4, parse out any Delereturn replies. */
2529 if (ret > 0 && nd->nd_repstat != 0 &&
2530 (nd->nd_flag & ND_NOMOREDATA)) {
2532 * If the Delegreturn failed, try again without
2533 * it. The server will Recall, as required.
2535 mbuf_freem(nd->nd_mrep);
2538 for (i = 0; i < (ret * 2); i++) {
2539 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
2541 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2543 if (i == 0 && ret > 1) {
2545 * If the Delegreturn failed, try again
2546 * without it. The server will Recall, as
2548 * If ret > 1, the first iteration of this
2549 * loop is the second DelegReturn result.
2551 mbuf_freem(nd->nd_mrep);
2554 nd->nd_flag |= ND_NOMOREDATA;
2559 /* Now, the first wcc attribute reply. */
2560 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
2561 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2563 nd->nd_flag |= ND_NOMOREDATA;
2565 error = nfscl_wcc_data(nd, fdvp, fnap, fattrflagp, NULL,
2567 /* and the second wcc attribute reply. */
2568 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 &&
2570 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2572 nd->nd_flag |= ND_NOMOREDATA;
2575 error = nfscl_wcc_data(nd, tdvp, tnap, tattrflagp,
2578 if (nd->nd_repstat && !error)
2579 error = nd->nd_repstat;
2581 mbuf_freem(nd->nd_mrep);
2586 * nfs hard link create rpc
2589 nfsrpc_link(vnode_t dvp, vnode_t vp, char *name, int namelen,
2590 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
2591 struct nfsvattr *nap, int *attrflagp, int *dattrflagp, void *dstuff)
2594 struct nfsrv_descript nfsd, *nd = &nfsd;
2595 nfsattrbit_t attrbits;
2600 if (namelen > NFS_MAXNAMLEN)
2601 return (ENAMETOOLONG);
2602 NFSCL_REQSTART(nd, NFSPROC_LINK, vp);
2603 if (nd->nd_flag & ND_NFSV4) {
2604 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2605 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2607 (void) nfsm_fhtom(nd, VTONFS(dvp)->n_fhp->nfh_fh,
2608 VTONFS(dvp)->n_fhp->nfh_len, 0);
2609 if (nd->nd_flag & ND_NFSV4) {
2610 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2611 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2612 NFSWCCATTR_ATTRBIT(&attrbits);
2613 (void) nfsrv_putattrbit(nd, &attrbits);
2614 nd->nd_flag |= ND_V4WCCATTR;
2615 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2616 *tl = txdr_unsigned(NFSV4OP_LINK);
2618 (void) nfsm_strtom(nd, name, namelen);
2619 error = nfscl_request(nd, vp, p, cred, dstuff);
2622 if (nd->nd_flag & ND_NFSV3) {
2623 error = nfscl_postop_attr(nd, nap, attrflagp, dstuff);
2625 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp,
2627 } else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
2629 * First, parse out the PutFH and Getattr result.
2631 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2633 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2635 nd->nd_flag |= ND_NOMOREDATA;
2637 * Get the pre-op attributes.
2639 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2641 if (nd->nd_repstat && !error)
2642 error = nd->nd_repstat;
2644 mbuf_freem(nd->nd_mrep);
2649 * nfs symbolic link create rpc
2652 nfsrpc_symlink(vnode_t dvp, char *name, int namelen, const char *target,
2653 struct vattr *vap, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
2654 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
2655 int *dattrflagp, void *dstuff)
2658 struct nfsrv_descript nfsd, *nd = &nfsd;
2659 struct nfsmount *nmp;
2660 int slen, error = 0;
2665 nmp = VFSTONFS(vnode_mount(dvp));
2666 slen = strlen(target);
2667 if (slen > NFS_MAXPATHLEN || namelen > NFS_MAXNAMLEN)
2668 return (ENAMETOOLONG);
2669 NFSCL_REQSTART(nd, NFSPROC_SYMLINK, dvp);
2670 if (nd->nd_flag & ND_NFSV4) {
2671 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2672 *tl = txdr_unsigned(NFLNK);
2673 (void) nfsm_strtom(nd, target, slen);
2675 (void) nfsm_strtom(nd, name, namelen);
2676 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
2677 nfscl_fillsattr(nd, vap, dvp, 0, 0);
2678 if (!(nd->nd_flag & ND_NFSV4))
2679 (void) nfsm_strtom(nd, target, slen);
2680 if (nd->nd_flag & ND_NFSV2)
2681 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0);
2682 error = nfscl_request(nd, dvp, p, cred, dstuff);
2685 if (nd->nd_flag & ND_NFSV4)
2686 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2687 if ((nd->nd_flag & ND_NFSV3) && !error) {
2688 if (!nd->nd_repstat)
2689 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
2691 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp,
2694 if (nd->nd_repstat && !error)
2695 error = nd->nd_repstat;
2696 mbuf_freem(nd->nd_mrep);
2698 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
2699 * Only do this if vfs.nfs.ignore_eexist is set.
2700 * Never do this for NFSv4.1 or later minor versions, since sessions
2701 * should guarantee "exactly once" RPC semantics.
2703 if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) ||
2704 nmp->nm_minorvers == 0))
2713 nfsrpc_mkdir(vnode_t dvp, char *name, int namelen, struct vattr *vap,
2714 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
2715 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
2716 int *dattrflagp, void *dstuff)
2719 struct nfsrv_descript nfsd, *nd = &nfsd;
2720 nfsattrbit_t attrbits;
2723 struct nfsmount *nmp;
2728 nmp = VFSTONFS(vnode_mount(dvp));
2729 fhp = VTONFS(dvp)->n_fhp;
2730 if (namelen > NFS_MAXNAMLEN)
2731 return (ENAMETOOLONG);
2732 NFSCL_REQSTART(nd, NFSPROC_MKDIR, dvp);
2733 if (nd->nd_flag & ND_NFSV4) {
2734 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2735 *tl = txdr_unsigned(NFDIR);
2737 (void) nfsm_strtom(nd, name, namelen);
2738 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0);
2739 if (nd->nd_flag & ND_NFSV4) {
2740 NFSGETATTR_ATTRBIT(&attrbits);
2741 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2742 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
2743 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2744 (void) nfsrv_putattrbit(nd, &attrbits);
2745 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2746 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2747 (void) nfsm_fhtom(nd, fhp->nfh_fh, fhp->nfh_len, 0);
2748 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2749 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2750 (void) nfsrv_putattrbit(nd, &attrbits);
2752 error = nfscl_request(nd, dvp, p, cred, dstuff);
2755 if (nd->nd_flag & ND_NFSV4)
2756 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2757 if (!nd->nd_repstat && !error) {
2758 if (nd->nd_flag & ND_NFSV4) {
2759 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2760 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
2763 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
2764 if (error == 0 && (nd->nd_flag & ND_NFSV4) != 0) {
2765 /* Get rid of the PutFH and Getattr status values. */
2766 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
2767 /* Load the directory attributes. */
2768 error = nfsm_loadattr(nd, dnap);
2773 if ((nd->nd_flag & ND_NFSV3) && !error)
2774 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2775 if (nd->nd_repstat && !error)
2776 error = nd->nd_repstat;
2778 mbuf_freem(nd->nd_mrep);
2780 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
2781 * Only do this if vfs.nfs.ignore_eexist is set.
2782 * Never do this for NFSv4.1 or later minor versions, since sessions
2783 * should guarantee "exactly once" RPC semantics.
2785 if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) ||
2786 nmp->nm_minorvers == 0))
2792 * nfs remove directory call
2795 nfsrpc_rmdir(vnode_t dvp, char *name, int namelen, struct ucred *cred,
2796 NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp, void *dstuff)
2798 struct nfsrv_descript nfsd, *nd = &nfsd;
2802 if (namelen > NFS_MAXNAMLEN)
2803 return (ENAMETOOLONG);
2804 NFSCL_REQSTART(nd, NFSPROC_RMDIR, dvp);
2805 (void) nfsm_strtom(nd, name, namelen);
2806 error = nfscl_request(nd, dvp, p, cred, dstuff);
2809 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
2810 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2811 if (nd->nd_repstat && !error)
2812 error = nd->nd_repstat;
2813 mbuf_freem(nd->nd_mrep);
2815 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
2817 if (error == ENOENT)
2824 * Always returns with either uio_resid unchanged, if you are at the
2825 * end of the directory, or uio_resid == 0, with all DIRBLKSIZ chunks
2827 * I felt this would allow caching of directory blocks more easily
2828 * than returning a pertially filled block.
2829 * Directory offset cookies:
2830 * Oh my, what to do with them...
2831 * I can think of three ways to deal with them:
2832 * 1 - have the layer above these RPCs maintain a map between logical
2833 * directory byte offsets and the NFS directory offset cookies
2834 * 2 - pass the opaque directory offset cookies up into userland
2835 * and let the libc functions deal with them, via the system call
2836 * 3 - return them to userland in the "struct dirent", so future versions
2837 * of libc can use them and do whatever is necessary to make things work
2838 * above these rpc calls, in the meantime
2839 * For now, I do #3 by "hiding" the directory offset cookies after the
2840 * d_name field in struct dirent. This is space inside d_reclen that
2841 * will be ignored by anything that doesn't know about them.
2842 * The directory offset cookies are filled in as the last 8 bytes of
2843 * each directory entry, after d_name. Someday, the userland libc
2844 * functions may be able to use these. In the meantime, it satisfies
2845 * OpenBSD's requirements for cookies being returned.
2846 * If expects the directory offset cookie for the read to be in uio_offset
2847 * and returns the one for the next entry after this directory block in
2851 nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
2852 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
2853 int *eofp, void *stuff)
2856 struct dirent *dp = NULL;
2858 nfsquad_t cookie, ncookie;
2859 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
2860 struct nfsnode *dnp = VTONFS(vp);
2861 struct nfsvattr nfsva;
2862 struct nfsrv_descript nfsd, *nd = &nfsd;
2863 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
2864 int reqsize, tryformoredirs = 1, readsize, eof = 0, gotmnton = 0;
2865 u_int64_t dotfileid, dotdotfileid = 0, fakefileno = UINT64_MAX;
2867 nfsattrbit_t attrbits, dattrbits;
2868 u_int32_t rderr, *tl2 = NULL;
2871 KASSERT(uiop->uio_iovcnt == 1 &&
2872 (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0,
2873 ("nfs readdirrpc bad uio"));
2874 ncookie.lval[0] = ncookie.lval[1] = 0;
2876 * There is no point in reading a lot more than uio_resid, however
2877 * adding one additional DIRBLKSIZ makes sense. Since uio_resid
2878 * and nm_readdirsize are both exact multiples of DIRBLKSIZ, this
2879 * will never make readsize > nm_readdirsize.
2881 readsize = nmp->nm_readdirsize;
2882 if (readsize > uio_uio_resid(uiop))
2883 readsize = uio_uio_resid(uiop) + DIRBLKSIZ;
2888 tresid = uio_uio_resid(uiop);
2889 cookie.lval[0] = cookiep->nfsuquad[0];
2890 cookie.lval[1] = cookiep->nfsuquad[1];
2894 * For NFSv4, first create the "." and ".." entries.
2896 if (NFSHASNFSV4(nmp)) {
2897 reqsize = 6 * NFSX_UNSIGNED;
2898 NFSGETATTR_ATTRBIT(&dattrbits);
2899 NFSZERO_ATTRBIT(&attrbits);
2900 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID);
2901 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TYPE);
2902 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
2903 NFSATTRBIT_MOUNTEDONFILEID)) {
2904 NFSSETBIT_ATTRBIT(&attrbits,
2905 NFSATTRBIT_MOUNTEDONFILEID);
2909 * Must fake it. Use the fileno, except when the
2910 * fsid is != to that of the directory. For that
2911 * case, generate a fake fileno that is not the same.
2913 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID);
2918 * Joy, oh joy. For V4 we get to hand craft '.' and '..'.
2920 if (uiop->uio_offset == 0) {
2921 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp);
2922 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2923 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
2924 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2925 (void) nfsrv_putattrbit(nd, &attrbits);
2926 error = nfscl_request(nd, vp, p, cred, stuff);
2929 dotfileid = 0; /* Fake out the compiler. */
2930 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
2931 error = nfsm_loadattr(nd, &nfsva);
2934 dotfileid = nfsva.na_fileid;
2936 if (nd->nd_repstat == 0) {
2937 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2938 len = fxdr_unsigned(int, *(tl + 4));
2939 if (len > 0 && len <= NFSX_V4FHMAX)
2940 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
2944 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
2945 nfsva.na_mntonfileno = UINT64_MAX;
2946 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
2947 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
2948 NULL, NULL, NULL, p, cred);
2950 dotdotfileid = dotfileid;
2951 } else if (gotmnton) {
2952 if (nfsva.na_mntonfileno != UINT64_MAX)
2953 dotdotfileid = nfsva.na_mntonfileno;
2955 dotdotfileid = nfsva.na_fileid;
2956 } else if (nfsva.na_filesid[0] ==
2957 dnp->n_vattr.na_filesid[0] &&
2958 nfsva.na_filesid[1] ==
2959 dnp->n_vattr.na_filesid[1]) {
2960 dotdotfileid = nfsva.na_fileid;
2964 } while (fakefileno ==
2966 dotdotfileid = fakefileno;
2969 } else if (nd->nd_repstat == NFSERR_NOENT) {
2971 * Lookupp returns NFSERR_NOENT when we are
2972 * at the root, so just use the current dir.
2975 dotdotfileid = dotfileid;
2977 error = nd->nd_repstat;
2979 mbuf_freem(nd->nd_mrep);
2983 dp = (struct dirent *)uio_iov_base(uiop);
2984 dp->d_pad0 = dp->d_pad1 = 0;
2986 dp->d_type = DT_DIR;
2987 dp->d_fileno = dotfileid;
2989 *((uint64_t *)dp->d_name) = 0; /* Zero pad it. */
2990 dp->d_name[0] = '.';
2991 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER;
2993 * Just make these offset cookie 0.
2995 tl = (u_int32_t *)&dp->d_name[8];
2998 blksiz += dp->d_reclen;
2999 uio_uio_resid_add(uiop, -(dp->d_reclen));
3000 uiop->uio_offset += dp->d_reclen;
3001 uio_iov_base_add(uiop, dp->d_reclen);
3002 uio_iov_len_add(uiop, -(dp->d_reclen));
3003 dp = (struct dirent *)uio_iov_base(uiop);
3004 dp->d_pad0 = dp->d_pad1 = 0;
3006 dp->d_type = DT_DIR;
3007 dp->d_fileno = dotdotfileid;
3009 *((uint64_t *)dp->d_name) = 0;
3010 dp->d_name[0] = '.';
3011 dp->d_name[1] = '.';
3012 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER;
3014 * Just make these offset cookie 0.
3016 tl = (u_int32_t *)&dp->d_name[8];
3019 blksiz += dp->d_reclen;
3020 uio_uio_resid_add(uiop, -(dp->d_reclen));
3021 uiop->uio_offset += dp->d_reclen;
3022 uio_iov_base_add(uiop, dp->d_reclen);
3023 uio_iov_len_add(uiop, -(dp->d_reclen));
3025 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_RDATTRERROR);
3027 reqsize = 5 * NFSX_UNSIGNED;
3032 * Loop around doing readdir rpc's of size readsize.
3033 * The stopping criteria is EOF or buffer full.
3035 while (more_dirs && bigenough) {
3037 NFSCL_REQSTART(nd, NFSPROC_READDIR, vp);
3038 if (nd->nd_flag & ND_NFSV2) {
3039 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3040 *tl++ = cookie.lval[1];
3041 *tl = txdr_unsigned(readsize);
3043 NFSM_BUILD(tl, u_int32_t *, reqsize);
3044 *tl++ = cookie.lval[0];
3045 *tl++ = cookie.lval[1];
3046 if (cookie.qval == 0) {
3051 *tl++ = dnp->n_cookieverf.nfsuquad[0];
3052 *tl++ = dnp->n_cookieverf.nfsuquad[1];
3055 if (nd->nd_flag & ND_NFSV4) {
3056 *tl++ = txdr_unsigned(readsize);
3057 *tl = txdr_unsigned(readsize);
3058 (void) nfsrv_putattrbit(nd, &attrbits);
3059 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3060 *tl = txdr_unsigned(NFSV4OP_GETATTR);
3061 (void) nfsrv_putattrbit(nd, &dattrbits);
3063 *tl = txdr_unsigned(readsize);
3066 error = nfscl_request(nd, vp, p, cred, stuff);
3069 if (!(nd->nd_flag & ND_NFSV2)) {
3070 if (nd->nd_flag & ND_NFSV3)
3071 error = nfscl_postop_attr(nd, nap, attrflagp,
3073 if (!nd->nd_repstat && !error) {
3074 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3076 dnp->n_cookieverf.nfsuquad[0] = *tl++;
3077 dnp->n_cookieverf.nfsuquad[1] = *tl;
3081 if (nd->nd_repstat || error) {
3083 error = nd->nd_repstat;
3086 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3087 more_dirs = fxdr_unsigned(int, *tl);
3091 /* loop through the dir entries, doctoring them to 4bsd form */
3092 while (more_dirs && bigenough) {
3093 if (nd->nd_flag & ND_NFSV4) {
3094 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3095 ncookie.lval[0] = *tl++;
3096 ncookie.lval[1] = *tl++;
3097 len = fxdr_unsigned(int, *tl);
3098 } else if (nd->nd_flag & ND_NFSV3) {
3099 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3100 nfsva.na_fileid = fxdr_hyper(tl);
3102 len = fxdr_unsigned(int, *tl);
3104 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
3105 nfsva.na_fileid = fxdr_unsigned(uint64_t,
3107 len = fxdr_unsigned(int, *tl);
3109 if (len <= 0 || len > NFS_MAXNAMLEN) {
3113 tlen = roundup2(len, 8);
3115 tlen += 8; /* To ensure null termination. */
3116 left = DIRBLKSIZ - blksiz;
3117 if (_GENERIC_DIRLEN(len) + NFSX_HYPER > left) {
3118 NFSBZERO(uio_iov_base(uiop), left);
3119 dp->d_reclen += left;
3120 uio_iov_base_add(uiop, left);
3121 uio_iov_len_add(uiop, -(left));
3122 uio_uio_resid_add(uiop, -(left));
3123 uiop->uio_offset += left;
3126 if (_GENERIC_DIRLEN(len) + NFSX_HYPER >
3127 uio_uio_resid(uiop))
3130 dp = (struct dirent *)uio_iov_base(uiop);
3131 dp->d_pad0 = dp->d_pad1 = 0;
3134 dp->d_reclen = _GENERIC_DIRLEN(len) +
3136 dp->d_type = DT_UNKNOWN;
3137 blksiz += dp->d_reclen;
3138 if (blksiz == DIRBLKSIZ)
3140 uio_uio_resid_add(uiop, -(DIRHDSIZ));
3141 uiop->uio_offset += DIRHDSIZ;
3142 uio_iov_base_add(uiop, DIRHDSIZ);
3143 uio_iov_len_add(uiop, -(DIRHDSIZ));
3144 error = nfsm_mbufuio(nd, uiop, len);
3147 cp = uio_iov_base(uiop);
3150 cp += tlen; /* points to cookie storage */
3151 tl2 = (u_int32_t *)cp;
3152 uio_iov_base_add(uiop, (tlen + NFSX_HYPER));
3153 uio_iov_len_add(uiop, -(tlen + NFSX_HYPER));
3154 uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER));
3155 uiop->uio_offset += (tlen + NFSX_HYPER);
3157 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
3161 if (nd->nd_flag & ND_NFSV4) {
3163 nfsva.na_mntonfileno = UINT64_MAX;
3164 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
3165 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
3166 NULL, NULL, &rderr, p, cred);
3169 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3170 } else if (nd->nd_flag & ND_NFSV3) {
3171 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3172 ncookie.lval[0] = *tl++;
3173 ncookie.lval[1] = *tl++;
3175 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
3176 ncookie.lval[0] = 0;
3177 ncookie.lval[1] = *tl++;
3180 if (nd->nd_flag & ND_NFSV4) {
3185 if (nfsva.na_mntonfileno != UINT64_MAX)
3186 dp->d_fileno = nfsva.na_mntonfileno;
3188 dp->d_fileno = nfsva.na_fileid;
3189 } else if (nfsva.na_filesid[0] ==
3190 dnp->n_vattr.na_filesid[0] &&
3191 nfsva.na_filesid[1] ==
3192 dnp->n_vattr.na_filesid[1]) {
3193 dp->d_fileno = nfsva.na_fileid;
3197 } while (fakefileno ==
3199 dp->d_fileno = fakefileno;
3201 dp->d_type = vtonfs_dtype(nfsva.na_type);
3204 dp->d_fileno = nfsva.na_fileid;
3206 *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] =
3208 *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] =
3211 more_dirs = fxdr_unsigned(int, *tl);
3214 * If at end of rpc data, get the eof boolean
3217 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3218 eof = fxdr_unsigned(int, *tl);
3221 if (nd->nd_flag & ND_NFSV4) {
3222 error = nfscl_postop_attr(nd, nap, attrflagp,
3228 mbuf_freem(nd->nd_mrep);
3232 * Fill last record, iff any, out to a multiple of DIRBLKSIZ
3233 * by increasing d_reclen for the last record.
3236 left = DIRBLKSIZ - blksiz;
3237 NFSBZERO(uio_iov_base(uiop), left);
3238 dp->d_reclen += left;
3239 uio_iov_base_add(uiop, left);
3240 uio_iov_len_add(uiop, -(left));
3241 uio_uio_resid_add(uiop, -(left));
3242 uiop->uio_offset += left;
3246 * If returning no data, assume end of file.
3247 * If not bigenough, return not end of file, since you aren't
3248 * returning all the data
3249 * Otherwise, return the eof flag from the server.
3252 if (tresid == ((size_t)(uio_uio_resid(uiop))))
3254 else if (!bigenough)
3261 * Add extra empty records to any remaining DIRBLKSIZ chunks.
3263 while (uio_uio_resid(uiop) > 0 && uio_uio_resid(uiop) != tresid) {
3264 dp = (struct dirent *)uio_iov_base(uiop);
3265 NFSBZERO(dp, DIRBLKSIZ);
3266 dp->d_type = DT_UNKNOWN;
3267 tl = (u_int32_t *)&dp->d_name[4];
3268 *tl++ = cookie.lval[0];
3269 *tl = cookie.lval[1];
3270 dp->d_reclen = DIRBLKSIZ;
3271 uio_iov_base_add(uiop, DIRBLKSIZ);
3272 uio_iov_len_add(uiop, -(DIRBLKSIZ));
3273 uio_uio_resid_add(uiop, -(DIRBLKSIZ));
3274 uiop->uio_offset += DIRBLKSIZ;
3278 if (nd->nd_mrep != NULL)
3279 mbuf_freem(nd->nd_mrep);
3285 * NFS V3 readdir plus RPC. Used in place of nfsrpc_readdir().
3286 * (Also used for NFS V4 when mount flag set.)
3287 * (ditto above w.r.t. multiple of DIRBLKSIZ, etc.)
3290 nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
3291 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
3292 int *eofp, void *stuff)
3295 struct dirent *dp = NULL;
3297 vnode_t newvp = NULLVP;
3298 struct nfsrv_descript nfsd, *nd = &nfsd;
3299 struct nameidata nami, *ndp = &nami;
3300 struct componentname *cnp = &ndp->ni_cnd;
3301 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
3302 struct nfsnode *dnp = VTONFS(vp), *np;
3303 struct nfsvattr nfsva;
3305 nfsquad_t cookie, ncookie;
3306 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
3307 int attrflag, tryformoredirs = 1, eof = 0, gotmnton = 0;
3308 int isdotdot = 0, unlocknewvp = 0;
3309 u_int64_t dotfileid, dotdotfileid = 0, fakefileno = UINT64_MAX;
3310 u_int64_t fileno = 0;
3312 nfsattrbit_t attrbits, dattrbits;
3314 u_int32_t *tl2 = NULL, rderr;
3315 struct timespec dctime;
3317 KASSERT(uiop->uio_iovcnt == 1 &&
3318 (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0,
3319 ("nfs readdirplusrpc bad uio"));
3320 ncookie.lval[0] = ncookie.lval[1] = 0;
3321 timespecclear(&dctime);
3327 cookie.lval[0] = cookiep->nfsuquad[0];
3328 cookie.lval[1] = cookiep->nfsuquad[1];
3329 tresid = uio_uio_resid(uiop);
3332 * For NFSv4, first create the "." and ".." entries.
3334 if (NFSHASNFSV4(nmp)) {
3335 NFSGETATTR_ATTRBIT(&dattrbits);
3336 NFSZERO_ATTRBIT(&attrbits);
3337 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID);
3338 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
3339 NFSATTRBIT_MOUNTEDONFILEID)) {
3340 NFSSETBIT_ATTRBIT(&attrbits,
3341 NFSATTRBIT_MOUNTEDONFILEID);
3345 * Must fake it. Use the fileno, except when the
3346 * fsid is != to that of the directory. For that
3347 * case, generate a fake fileno that is not the same.
3349 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID);
3354 * Joy, oh joy. For V4 we get to hand craft '.' and '..'.
3356 if (uiop->uio_offset == 0) {
3357 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp);
3358 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3359 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
3360 *tl = txdr_unsigned(NFSV4OP_GETATTR);
3361 (void) nfsrv_putattrbit(nd, &attrbits);
3362 error = nfscl_request(nd, vp, p, cred, stuff);
3365 dotfileid = 0; /* Fake out the compiler. */
3366 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
3367 error = nfsm_loadattr(nd, &nfsva);
3370 dctime = nfsva.na_ctime;
3371 dotfileid = nfsva.na_fileid;
3373 if (nd->nd_repstat == 0) {
3374 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
3375 len = fxdr_unsigned(int, *(tl + 4));
3376 if (len > 0 && len <= NFSX_V4FHMAX)
3377 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
3381 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
3382 nfsva.na_mntonfileno = UINT64_MAX;
3383 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
3384 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
3385 NULL, NULL, NULL, p, cred);
3387 dotdotfileid = dotfileid;
3388 } else if (gotmnton) {
3389 if (nfsva.na_mntonfileno != UINT64_MAX)
3390 dotdotfileid = nfsva.na_mntonfileno;
3392 dotdotfileid = nfsva.na_fileid;
3393 } else if (nfsva.na_filesid[0] ==
3394 dnp->n_vattr.na_filesid[0] &&
3395 nfsva.na_filesid[1] ==
3396 dnp->n_vattr.na_filesid[1]) {
3397 dotdotfileid = nfsva.na_fileid;
3401 } while (fakefileno ==
3403 dotdotfileid = fakefileno;
3406 } else if (nd->nd_repstat == NFSERR_NOENT) {
3408 * Lookupp returns NFSERR_NOENT when we are
3409 * at the root, so just use the current dir.
3412 dotdotfileid = dotfileid;
3414 error = nd->nd_repstat;
3416 mbuf_freem(nd->nd_mrep);
3420 dp = (struct dirent *)uio_iov_base(uiop);
3421 dp->d_pad0 = dp->d_pad1 = 0;
3423 dp->d_type = DT_DIR;
3424 dp->d_fileno = dotfileid;
3426 *((uint64_t *)dp->d_name) = 0; /* Zero pad it. */
3427 dp->d_name[0] = '.';
3428 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER;
3430 * Just make these offset cookie 0.
3432 tl = (u_int32_t *)&dp->d_name[8];
3435 blksiz += dp->d_reclen;
3436 uio_uio_resid_add(uiop, -(dp->d_reclen));
3437 uiop->uio_offset += dp->d_reclen;
3438 uio_iov_base_add(uiop, dp->d_reclen);
3439 uio_iov_len_add(uiop, -(dp->d_reclen));
3440 dp = (struct dirent *)uio_iov_base(uiop);
3441 dp->d_pad0 = dp->d_pad1 = 0;
3443 dp->d_type = DT_DIR;
3444 dp->d_fileno = dotdotfileid;
3446 *((uint64_t *)dp->d_name) = 0;
3447 dp->d_name[0] = '.';
3448 dp->d_name[1] = '.';
3449 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER;
3451 * Just make these offset cookie 0.
3453 tl = (u_int32_t *)&dp->d_name[8];
3456 blksiz += dp->d_reclen;
3457 uio_uio_resid_add(uiop, -(dp->d_reclen));
3458 uiop->uio_offset += dp->d_reclen;
3459 uio_iov_base_add(uiop, dp->d_reclen);
3460 uio_iov_len_add(uiop, -(dp->d_reclen));
3462 NFSREADDIRPLUS_ATTRBIT(&attrbits);
3464 NFSSETBIT_ATTRBIT(&attrbits,
3465 NFSATTRBIT_MOUNTEDONFILEID);
3469 * Loop around doing readdir rpc's of size nm_readdirsize.
3470 * The stopping criteria is EOF or buffer full.
3472 while (more_dirs && bigenough) {
3474 NFSCL_REQSTART(nd, NFSPROC_READDIRPLUS, vp);
3475 NFSM_BUILD(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
3476 *tl++ = cookie.lval[0];
3477 *tl++ = cookie.lval[1];
3478 if (cookie.qval == 0) {
3483 *tl++ = dnp->n_cookieverf.nfsuquad[0];
3484 *tl++ = dnp->n_cookieverf.nfsuquad[1];
3487 *tl++ = txdr_unsigned(nmp->nm_readdirsize);
3488 *tl = txdr_unsigned(nmp->nm_readdirsize);
3489 if (nd->nd_flag & ND_NFSV4) {
3490 (void) nfsrv_putattrbit(nd, &attrbits);
3491 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3492 *tl = txdr_unsigned(NFSV4OP_GETATTR);
3493 (void) nfsrv_putattrbit(nd, &dattrbits);
3495 error = nfscl_request(nd, vp, p, cred, stuff);
3498 if (nd->nd_flag & ND_NFSV3)
3499 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3500 if (nd->nd_repstat || error) {
3502 error = nd->nd_repstat;
3505 if ((nd->nd_flag & ND_NFSV3) != 0 && *attrflagp != 0)
3506 dctime = nap->na_ctime;
3507 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3509 dnp->n_cookieverf.nfsuquad[0] = *tl++;
3510 dnp->n_cookieverf.nfsuquad[1] = *tl++;
3512 more_dirs = fxdr_unsigned(int, *tl);
3516 /* loop through the dir entries, doctoring them to 4bsd form */
3517 while (more_dirs && bigenough) {
3518 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3519 if (nd->nd_flag & ND_NFSV4) {
3520 ncookie.lval[0] = *tl++;
3521 ncookie.lval[1] = *tl++;
3523 fileno = fxdr_hyper(tl);
3526 len = fxdr_unsigned(int, *tl);
3527 if (len <= 0 || len > NFS_MAXNAMLEN) {
3531 tlen = roundup2(len, 8);
3533 tlen += 8; /* To ensure null termination. */
3534 left = DIRBLKSIZ - blksiz;
3535 if (_GENERIC_DIRLEN(len) + NFSX_HYPER > left) {
3536 NFSBZERO(uio_iov_base(uiop), left);
3537 dp->d_reclen += left;
3538 uio_iov_base_add(uiop, left);
3539 uio_iov_len_add(uiop, -(left));
3540 uio_uio_resid_add(uiop, -(left));
3541 uiop->uio_offset += left;
3544 if (_GENERIC_DIRLEN(len) + NFSX_HYPER >
3545 uio_uio_resid(uiop))
3548 dp = (struct dirent *)uio_iov_base(uiop);
3549 dp->d_pad0 = dp->d_pad1 = 0;
3552 dp->d_reclen = _GENERIC_DIRLEN(len) +
3554 dp->d_type = DT_UNKNOWN;
3555 blksiz += dp->d_reclen;
3556 if (blksiz == DIRBLKSIZ)
3558 uio_uio_resid_add(uiop, -(DIRHDSIZ));
3559 uiop->uio_offset += DIRHDSIZ;
3560 uio_iov_base_add(uiop, DIRHDSIZ);
3561 uio_iov_len_add(uiop, -(DIRHDSIZ));
3562 cnp->cn_nameptr = uio_iov_base(uiop);
3563 cnp->cn_namelen = len;
3565 error = nfsm_mbufuio(nd, uiop, len);
3568 cp = uio_iov_base(uiop);
3571 cp += tlen; /* points to cookie storage */
3572 tl2 = (u_int32_t *)cp;
3573 if (len == 2 && cnp->cn_nameptr[0] == '.' &&
3574 cnp->cn_nameptr[1] == '.')
3578 uio_iov_base_add(uiop, (tlen + NFSX_HYPER));
3579 uio_iov_len_add(uiop, -(tlen + NFSX_HYPER));
3580 uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER));
3581 uiop->uio_offset += (tlen + NFSX_HYPER);
3583 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
3588 if (nd->nd_flag & ND_NFSV3) {
3589 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3590 ncookie.lval[0] = *tl++;
3591 ncookie.lval[1] = *tl++;
3592 attrflag = fxdr_unsigned(int, *tl);
3594 error = nfsm_loadattr(nd, &nfsva);
3598 NFSM_DISSECT(tl,u_int32_t *,NFSX_UNSIGNED);
3600 error = nfsm_getfh(nd, &nfhp);
3604 if (!attrflag && nfhp != NULL) {
3605 free(nfhp, M_NFSFH);
3610 nfsva.na_mntonfileno = 0xffffffff;
3611 error = nfsv4_loadattr(nd, NULL, &nfsva, &nfhp,
3612 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
3613 NULL, NULL, &rderr, p, cred);
3619 if (nd->nd_flag & ND_NFSV4) {
3622 } else if (gotmnton) {
3623 if (nfsva.na_mntonfileno != 0xffffffff)
3624 dp->d_fileno = nfsva.na_mntonfileno;
3626 dp->d_fileno = nfsva.na_fileid;
3627 } else if (nfsva.na_filesid[0] ==
3628 dnp->n_vattr.na_filesid[0] &&
3629 nfsva.na_filesid[1] ==
3630 dnp->n_vattr.na_filesid[1]) {
3631 dp->d_fileno = nfsva.na_fileid;
3635 } while (fakefileno ==
3637 dp->d_fileno = fakefileno;
3640 dp->d_fileno = fileno;
3642 *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] =
3644 *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] =
3648 if (NFSRV_CMPFH(nfhp->nfh_fh, nfhp->nfh_len,
3649 dnp->n_fhp->nfh_fh, dnp->n_fhp->nfh_len)) {
3653 free(nfhp, M_NFSFH);
3655 } else if (isdotdot != 0) {
3657 * Skip doing a nfscl_nget() call for "..".
3658 * There's a race between acquiring the nfs
3659 * node here and lookups that look for the
3660 * directory being read (in the parent).
3661 * It would try to get a lock on ".." here,
3662 * owning the lock on the directory being
3663 * read. Lookup will hold the lock on ".."
3664 * and try to acquire the lock on the
3665 * directory being read.
3666 * If the directory is unlocked/relocked,
3667 * then there is a LOR with the buflock
3670 free(nfhp, M_NFSFH);
3672 error = nfscl_nget(vnode_mount(vp), vp,
3673 nfhp, cnp, p, &np, NULL, LK_EXCLUSIVE);
3680 if (newvp != NULLVP) {
3681 error = nfscl_loadattrcache(&newvp,
3682 &nfsva, NULL, NULL, 0, 0);
3691 vtonfs_dtype(np->n_vattr.na_type);
3693 NFSCNHASH(cnp, HASHINIT);
3694 if (cnp->cn_namelen <= NCHNAMLEN &&
3695 (newvp->v_type != VDIR ||
3696 dctime.tv_sec != 0)) {
3697 cache_enter_time(ndp->ni_dvp,
3700 newvp->v_type != VDIR ? NULL :
3710 } else if (nfhp != NULL) {
3711 free(nfhp, M_NFSFH);
3713 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3714 more_dirs = fxdr_unsigned(int, *tl);
3717 * If at end of rpc data, get the eof boolean
3720 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3721 eof = fxdr_unsigned(int, *tl);
3724 if (nd->nd_flag & ND_NFSV4) {
3725 error = nfscl_postop_attr(nd, nap, attrflagp,
3731 mbuf_freem(nd->nd_mrep);
3735 * Fill last record, iff any, out to a multiple of DIRBLKSIZ
3736 * by increasing d_reclen for the last record.
3739 left = DIRBLKSIZ - blksiz;
3740 NFSBZERO(uio_iov_base(uiop), left);
3741 dp->d_reclen += left;
3742 uio_iov_base_add(uiop, left);
3743 uio_iov_len_add(uiop, -(left));
3744 uio_uio_resid_add(uiop, -(left));
3745 uiop->uio_offset += left;
3749 * If returning no data, assume end of file.
3750 * If not bigenough, return not end of file, since you aren't
3751 * returning all the data
3752 * Otherwise, return the eof flag from the server.
3755 if (tresid == uio_uio_resid(uiop))
3757 else if (!bigenough)
3764 * Add extra empty records to any remaining DIRBLKSIZ chunks.
3766 while (uio_uio_resid(uiop) > 0 && uio_uio_resid(uiop) != tresid) {
3767 dp = (struct dirent *)uio_iov_base(uiop);
3768 NFSBZERO(dp, DIRBLKSIZ);
3769 dp->d_type = DT_UNKNOWN;
3770 tl = (u_int32_t *)&dp->d_name[4];
3771 *tl++ = cookie.lval[0];
3772 *tl = cookie.lval[1];
3773 dp->d_reclen = DIRBLKSIZ;
3774 uio_iov_base_add(uiop, DIRBLKSIZ);
3775 uio_iov_len_add(uiop, -(DIRBLKSIZ));
3776 uio_uio_resid_add(uiop, -(DIRBLKSIZ));
3777 uiop->uio_offset += DIRBLKSIZ;
3781 if (nd->nd_mrep != NULL)
3782 mbuf_freem(nd->nd_mrep);
3791 nfsrpc_commit(vnode_t vp, u_quad_t offset, int cnt, struct ucred *cred,
3792 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
3795 struct nfsrv_descript nfsd, *nd = &nfsd;
3796 nfsattrbit_t attrbits;
3798 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
3801 NFSCL_REQSTART(nd, NFSPROC_COMMIT, vp);
3802 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3803 txdr_hyper(offset, tl);
3805 *tl = txdr_unsigned(cnt);
3806 if (nd->nd_flag & ND_NFSV4) {
3808 * And do a Getattr op.
3810 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3811 *tl = txdr_unsigned(NFSV4OP_GETATTR);
3812 NFSGETATTR_ATTRBIT(&attrbits);
3813 (void) nfsrv_putattrbit(nd, &attrbits);
3815 error = nfscl_request(nd, vp, p, cred, stuff);
3818 error = nfscl_wcc_data(nd, vp, nap, attrflagp, NULL, stuff);
3819 if (!error && !nd->nd_repstat) {
3820 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
3822 if (NFSBCMP(nmp->nm_verf, tl, NFSX_VERF)) {
3823 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
3824 nd->nd_repstat = NFSERR_STALEWRITEVERF;
3827 if (nd->nd_flag & ND_NFSV4)
3828 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3831 if (!error && nd->nd_repstat)
3832 error = nd->nd_repstat;
3833 mbuf_freem(nd->nd_mrep);
3838 * NFS byte range lock rpc.
3839 * (Mostly just calls one of the three lower level RPC routines.)
3842 nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
3843 int reclaim, struct ucred *cred, NFSPROC_T *p, void *id, int flags)
3845 struct nfscllockowner *lp;
3846 struct nfsclclient *clp;
3848 struct nfsrv_descript nfsd, *nd = &nfsd;
3849 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
3852 u_int32_t clidrev = 0;
3853 int error = 0, newone = 0, expireret = 0, retrycnt, donelocally;
3857 * Convert the flock structure into a start and end and do POSIX
3860 switch (fl->l_whence) {
3864 * Caller is responsible for adding any necessary offset
3865 * when SEEK_CUR is used.
3867 start = fl->l_start;
3871 start = size + fl->l_start;
3872 off = size + fl->l_start;
3879 if (fl->l_len != 0) {
3880 end = start + fl->l_len - 1;
3891 if (op == F_GETLK) {
3892 error = nfscl_getcl(vnode_mount(vp), cred, p, 1, &clp);
3895 error = nfscl_lockt(vp, clp, off, len, fl, p, id, flags);
3897 clidrev = clp->nfsc_clientidrev;
3898 error = nfsrpc_lockt(nd, vp, clp, off, len, fl, cred,
3900 } else if (error == -1) {
3903 nfscl_clientrelease(clp);
3904 } else if (op == F_UNLCK && fl->l_type == F_UNLCK) {
3906 * We must loop around for all lockowner cases.
3909 error = nfscl_getcl(vnode_mount(vp), cred, p, 1, &clp);
3913 error = nfscl_relbytelock(vp, off, len, cred, p, callcnt,
3914 clp, id, flags, &lp, &dorpc);
3916 * If it returns a NULL lp, we're done.
3920 nfscl_clientrelease(clp);
3922 nfscl_releasealllocks(clp, vp, p, id, flags);
3925 if (nmp->nm_clp != NULL)
3926 clidrev = nmp->nm_clp->nfsc_clientidrev;
3930 * If the server doesn't support Posix lock semantics,
3931 * only allow locks on the entire file, since it won't
3932 * handle overlapping byte ranges.
3933 * There might still be a problem when a lock
3934 * upgrade/downgrade (read<->write) occurs, since the
3935 * server "might" expect an unlock first?
3937 if (dorpc && (lp->nfsl_open->nfso_posixlock ||
3938 (off == 0 && len == NFS64BITSSET))) {
3940 * Since the lock records will go away, we must
3941 * wait for grace and delay here.
3944 error = nfsrpc_locku(nd, nmp, lp, off, len,
3945 NFSV4LOCKT_READ, cred, p, 0);
3946 if ((nd->nd_repstat == NFSERR_GRACE ||
3947 nd->nd_repstat == NFSERR_DELAY) &&
3949 (void) nfs_catnap(PZERO, (int)nd->nd_repstat,
3951 } while ((nd->nd_repstat == NFSERR_GRACE ||
3952 nd->nd_repstat == NFSERR_DELAY) && error == 0);
3955 } while (error == 0 && nd->nd_repstat == 0);
3956 nfscl_releasealllocks(clp, vp, p, id, flags);
3957 } else if (op == F_SETLK) {
3958 error = nfscl_getbytelock(vp, off, len, fl->l_type, cred, p,
3959 NULL, 0, id, flags, NULL, NULL, &lp, &newone, &donelocally);
3960 if (error || donelocally) {
3963 if (nmp->nm_clp != NULL)
3964 clidrev = nmp->nm_clp->nfsc_clientidrev;
3967 nfhp = VTONFS(vp)->n_fhp;
3968 if (!lp->nfsl_open->nfso_posixlock &&
3969 (off != 0 || len != NFS64BITSSET)) {
3972 error = nfsrpc_lock(nd, nmp, vp, nfhp->nfh_fh,
3973 nfhp->nfh_len, lp, newone, reclaim, off,
3974 len, fl->l_type, cred, p, 0);
3977 error = nd->nd_repstat;
3978 nfscl_lockrelease(lp, error, newone);
3983 error = nd->nd_repstat;
3984 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
3985 error == NFSERR_STALEDONTRECOVER ||
3986 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY ||
3987 error == NFSERR_BADSESSION) {
3988 (void) nfs_catnap(PZERO, error, "nfs_advlock");
3989 } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID)
3991 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
3994 } while (error == NFSERR_GRACE ||
3995 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY ||
3996 error == NFSERR_STALEDONTRECOVER || error == NFSERR_STALESTATEID ||
3997 error == NFSERR_BADSESSION ||
3998 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
3999 expireret == 0 && clidrev != 0 && retrycnt < 4));
4000 if (error && retrycnt >= 4)
4006 * The lower level routine for the LockT case.
4009 nfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp,
4010 struct nfsclclient *clp, u_int64_t off, u_int64_t len, struct flock *fl,
4011 struct ucred *cred, NFSPROC_T *p, void *id, int flags)
4014 int error, type, size;
4015 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
4017 struct nfsmount *nmp;
4018 struct nfsclsession *tsep;
4020 nmp = VFSTONFS(vp->v_mount);
4021 NFSCL_REQSTART(nd, NFSPROC_LOCKT, vp);
4022 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
4023 if (fl->l_type == F_RDLCK)
4024 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
4026 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
4027 txdr_hyper(off, tl);
4029 txdr_hyper(len, tl);
4031 tsep = nfsmnt_mdssession(nmp);
4032 *tl++ = tsep->nfsess_clientid.lval[0];
4033 *tl = tsep->nfsess_clientid.lval[1];
4034 nfscl_filllockowner(id, own, flags);
4036 NFSBCOPY(np->n_fhp->nfh_fh, &own[NFSV4CL_LOCKNAMELEN],
4037 np->n_fhp->nfh_len);
4038 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + np->n_fhp->nfh_len);
4039 error = nfscl_request(nd, vp, p, cred, NULL);
4042 if (nd->nd_repstat == 0) {
4043 fl->l_type = F_UNLCK;
4044 } else if (nd->nd_repstat == NFSERR_DENIED) {
4046 fl->l_whence = SEEK_SET;
4047 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
4048 fl->l_start = fxdr_hyper(tl);
4050 len = fxdr_hyper(tl);
4052 if (len == NFS64BITSSET)
4056 type = fxdr_unsigned(int, *tl++);
4057 if (type == NFSV4LOCKT_WRITE)
4058 fl->l_type = F_WRLCK;
4060 fl->l_type = F_RDLCK;
4062 * XXX For now, I have no idea what to do with the
4063 * conflicting lock_owner, so I'll just set the pid == 0
4064 * and skip over the lock_owner.
4066 fl->l_pid = (pid_t)0;
4068 size = fxdr_unsigned(int, *tl);
4069 if (size < 0 || size > NFSV4_OPAQUELIMIT)
4072 error = nfsm_advance(nd, NFSM_RNDUP(size), -1);
4073 } else if (nd->nd_repstat == NFSERR_STALECLIENTID)
4074 nfscl_initiate_recovery(clp);
4076 mbuf_freem(nd->nd_mrep);
4081 * Lower level function that performs the LockU RPC.
4084 nfsrpc_locku(struct nfsrv_descript *nd, struct nfsmount *nmp,
4085 struct nfscllockowner *lp, u_int64_t off, u_int64_t len,
4086 u_int32_t type, struct ucred *cred, NFSPROC_T *p, int syscred)
4091 nfscl_reqstart(nd, NFSPROC_LOCKU, nmp, lp->nfsl_open->nfso_fh,
4092 lp->nfsl_open->nfso_fhlen, NULL, NULL, 0, 0);
4093 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
4094 *tl++ = txdr_unsigned(type);
4095 *tl = txdr_unsigned(lp->nfsl_seqid);
4096 if (nfstest_outofseq &&
4097 (arc4random() % nfstest_outofseq) == 0)
4098 *tl = txdr_unsigned(lp->nfsl_seqid + 1);
4100 if (NFSHASNFSV4N(nmp))
4103 *tl++ = lp->nfsl_stateid.seqid;
4104 *tl++ = lp->nfsl_stateid.other[0];
4105 *tl++ = lp->nfsl_stateid.other[1];
4106 *tl++ = lp->nfsl_stateid.other[2];
4107 txdr_hyper(off, tl);
4109 txdr_hyper(len, tl);
4111 nd->nd_flag |= ND_USEGSSNAME;
4112 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4113 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4114 NFSCL_INCRSEQID(lp->nfsl_seqid, nd);
4117 if (nd->nd_repstat == 0) {
4118 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
4119 lp->nfsl_stateid.seqid = *tl++;
4120 lp->nfsl_stateid.other[0] = *tl++;
4121 lp->nfsl_stateid.other[1] = *tl++;
4122 lp->nfsl_stateid.other[2] = *tl;
4123 } else if (nd->nd_repstat == NFSERR_STALESTATEID)
4124 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp);
4126 mbuf_freem(nd->nd_mrep);
4131 * The actual Lock RPC.
4134 nfsrpc_lock(struct nfsrv_descript *nd, struct nfsmount *nmp, vnode_t vp,
4135 u_int8_t *nfhp, int fhlen, struct nfscllockowner *lp, int newone,
4136 int reclaim, u_int64_t off, u_int64_t len, short type, struct ucred *cred,
4137 NFSPROC_T *p, int syscred)
4141 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
4142 struct nfsclsession *tsep;
4144 nfscl_reqstart(nd, NFSPROC_LOCK, nmp, nfhp, fhlen, NULL, NULL, 0, 0);
4145 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
4146 if (type == F_RDLCK)
4147 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
4149 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
4150 *tl++ = txdr_unsigned(reclaim);
4151 txdr_hyper(off, tl);
4153 txdr_hyper(len, tl);
4157 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID +
4158 2 * NFSX_UNSIGNED + NFSX_HYPER);
4159 *tl++ = txdr_unsigned(lp->nfsl_open->nfso_own->nfsow_seqid);
4160 if (NFSHASNFSV4N(nmp))
4163 *tl++ = lp->nfsl_open->nfso_stateid.seqid;
4164 *tl++ = lp->nfsl_open->nfso_stateid.other[0];
4165 *tl++ = lp->nfsl_open->nfso_stateid.other[1];
4166 *tl++ = lp->nfsl_open->nfso_stateid.other[2];
4167 *tl++ = txdr_unsigned(lp->nfsl_seqid);
4168 tsep = nfsmnt_mdssession(nmp);
4169 *tl++ = tsep->nfsess_clientid.lval[0];
4170 *tl = tsep->nfsess_clientid.lval[1];
4171 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN);
4172 NFSBCOPY(nfhp, &own[NFSV4CL_LOCKNAMELEN], fhlen);
4173 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen);
4176 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
4177 if (NFSHASNFSV4N(nmp))
4180 *tl++ = lp->nfsl_stateid.seqid;
4181 *tl++ = lp->nfsl_stateid.other[0];
4182 *tl++ = lp->nfsl_stateid.other[1];
4183 *tl++ = lp->nfsl_stateid.other[2];
4184 *tl = txdr_unsigned(lp->nfsl_seqid);
4185 if (nfstest_outofseq &&
4186 (arc4random() % nfstest_outofseq) == 0)
4187 *tl = txdr_unsigned(lp->nfsl_seqid + 1);
4190 nd->nd_flag |= ND_USEGSSNAME;
4191 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
4192 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4196 NFSCL_INCRSEQID(lp->nfsl_open->nfso_own->nfsow_seqid, nd);
4197 NFSCL_INCRSEQID(lp->nfsl_seqid, nd);
4198 if (nd->nd_repstat == 0) {
4199 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
4200 lp->nfsl_stateid.seqid = *tl++;
4201 lp->nfsl_stateid.other[0] = *tl++;
4202 lp->nfsl_stateid.other[1] = *tl++;
4203 lp->nfsl_stateid.other[2] = *tl;
4204 } else if (nd->nd_repstat == NFSERR_DENIED) {
4205 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
4206 size = fxdr_unsigned(int, *(tl + 7));
4207 if (size < 0 || size > NFSV4_OPAQUELIMIT)
4210 error = nfsm_advance(nd, NFSM_RNDUP(size), -1);
4211 } else if (nd->nd_repstat == NFSERR_STALESTATEID)
4212 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp);
4214 mbuf_freem(nd->nd_mrep);
4220 * (always called with the vp for the mount point)
4223 nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp,
4224 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
4227 u_int32_t *tl = NULL;
4228 struct nfsrv_descript nfsd, *nd = &nfsd;
4229 struct nfsmount *nmp;
4230 nfsattrbit_t attrbits;
4234 nmp = VFSTONFS(vnode_mount(vp));
4235 if (NFSHASNFSV4(nmp)) {
4237 * For V4, you actually do a getattr.
4239 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
4240 NFSSTATFS_GETATTRBIT(&attrbits);
4241 (void) nfsrv_putattrbit(nd, &attrbits);
4242 nd->nd_flag |= ND_USEGSSNAME;
4243 error = nfscl_request(nd, vp, p, cred, stuff);
4246 if (nd->nd_repstat == 0) {
4247 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
4248 NULL, NULL, sbp, fsp, NULL, 0, NULL, NULL, NULL, p,
4251 nmp->nm_fsid[0] = nap->na_filesid[0];
4252 nmp->nm_fsid[1] = nap->na_filesid[1];
4253 NFSSETHASSETFSID(nmp);
4257 error = nd->nd_repstat;
4262 NFSCL_REQSTART(nd, NFSPROC_FSSTAT, vp);
4263 error = nfscl_request(nd, vp, p, cred, stuff);
4266 if (nd->nd_flag & ND_NFSV3) {
4267 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
4271 if (nd->nd_repstat) {
4272 error = nd->nd_repstat;
4275 NFSM_DISSECT(tl, u_int32_t *,
4276 NFSX_STATFS(nd->nd_flag & ND_NFSV3));
4278 if (NFSHASNFSV3(nmp)) {
4279 sbp->sf_tbytes = fxdr_hyper(tl); tl += 2;
4280 sbp->sf_fbytes = fxdr_hyper(tl); tl += 2;
4281 sbp->sf_abytes = fxdr_hyper(tl); tl += 2;
4282 sbp->sf_tfiles = fxdr_hyper(tl); tl += 2;
4283 sbp->sf_ffiles = fxdr_hyper(tl); tl += 2;
4284 sbp->sf_afiles = fxdr_hyper(tl); tl += 2;
4285 sbp->sf_invarsec = fxdr_unsigned(u_int32_t, *tl);
4286 } else if (NFSHASNFSV4(nmp) == 0) {
4287 sbp->sf_tsize = fxdr_unsigned(u_int32_t, *tl++);
4288 sbp->sf_bsize = fxdr_unsigned(u_int32_t, *tl++);
4289 sbp->sf_blocks = fxdr_unsigned(u_int32_t, *tl++);
4290 sbp->sf_bfree = fxdr_unsigned(u_int32_t, *tl++);
4291 sbp->sf_bavail = fxdr_unsigned(u_int32_t, *tl);
4294 mbuf_freem(nd->nd_mrep);
4302 nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc,
4303 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
4306 struct nfsrv_descript nfsd, *nd = &nfsd;
4307 struct nfsmount *nmp;
4309 nfsattrbit_t attrbits;
4313 nmp = VFSTONFS(vnode_mount(vp));
4314 if (NFSHASNFSV4(nmp)) {
4316 * For V4, you actually do a getattr.
4318 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
4319 NFSPATHCONF_GETATTRBIT(&attrbits);
4320 (void) nfsrv_putattrbit(nd, &attrbits);
4321 nd->nd_flag |= ND_USEGSSNAME;
4322 error = nfscl_request(nd, vp, p, cred, stuff);
4325 if (nd->nd_repstat == 0) {
4326 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
4327 pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, p,
4332 error = nd->nd_repstat;
4335 NFSCL_REQSTART(nd, NFSPROC_PATHCONF, vp);
4336 error = nfscl_request(nd, vp, p, cred, stuff);
4339 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
4340 if (nd->nd_repstat && !error)
4341 error = nd->nd_repstat;
4343 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3PATHCONF);
4344 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl++);
4345 pc->pc_namemax = fxdr_unsigned(u_int32_t, *tl++);
4346 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl++);
4347 pc->pc_chownrestricted =
4348 fxdr_unsigned(u_int32_t, *tl++);
4349 pc->pc_caseinsensitive =
4350 fxdr_unsigned(u_int32_t, *tl++);
4351 pc->pc_casepreserving = fxdr_unsigned(u_int32_t, *tl);
4355 mbuf_freem(nd->nd_mrep);
4360 * nfs version 3 fsinfo rpc call
4363 nfsrpc_fsinfo(vnode_t vp, struct nfsfsinfo *fsp, struct ucred *cred,
4364 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
4367 struct nfsrv_descript nfsd, *nd = &nfsd;
4371 NFSCL_REQSTART(nd, NFSPROC_FSINFO, vp);
4372 error = nfscl_request(nd, vp, p, cred, stuff);
4375 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
4376 if (nd->nd_repstat && !error)
4377 error = nd->nd_repstat;
4379 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3FSINFO);
4380 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *tl++);
4381 fsp->fs_rtpref = fxdr_unsigned(u_int32_t, *tl++);
4382 fsp->fs_rtmult = fxdr_unsigned(u_int32_t, *tl++);
4383 fsp->fs_wtmax = fxdr_unsigned(u_int32_t, *tl++);
4384 fsp->fs_wtpref = fxdr_unsigned(u_int32_t, *tl++);
4385 fsp->fs_wtmult = fxdr_unsigned(u_int32_t, *tl++);
4386 fsp->fs_dtpref = fxdr_unsigned(u_int32_t, *tl++);
4387 fsp->fs_maxfilesize = fxdr_hyper(tl);
4389 fxdr_nfsv3time(tl, &fsp->fs_timedelta);
4391 fsp->fs_properties = fxdr_unsigned(u_int32_t, *tl);
4394 mbuf_freem(nd->nd_mrep);
4399 * This function performs the Renew RPC.
4402 nfsrpc_renew(struct nfsclclient *clp, struct nfsclds *dsp, struct ucred *cred,
4406 struct nfsrv_descript nfsd;
4407 struct nfsrv_descript *nd = &nfsd;
4408 struct nfsmount *nmp;
4410 struct nfssockreq *nrp;
4411 struct nfsclsession *tsep;
4413 nmp = clp->nfsc_nmp;
4417 nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL, NULL, 0,
4420 nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL,
4421 &dsp->nfsclds_sess, 0, 0);
4422 if (!NFSHASNFSV4N(nmp)) {
4423 /* NFSv4.1 just uses a Sequence Op and not a Renew. */
4424 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4425 tsep = nfsmnt_mdssession(nmp);
4426 *tl++ = tsep->nfsess_clientid.lval[0];
4427 *tl = tsep->nfsess_clientid.lval[1];
4431 nrp = dsp->nfsclds_sockp;
4433 /* If NULL, use the MDS socket. */
4434 nrp = &nmp->nm_sockreq;
4435 nd->nd_flag |= ND_USEGSSNAME;
4437 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
4438 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4440 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
4441 NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
4443 nfscl_cancelreqs(dsp);
4447 error = nd->nd_repstat;
4448 mbuf_freem(nd->nd_mrep);
4453 * This function performs the Releaselockowner RPC.
4456 nfsrpc_rellockown(struct nfsmount *nmp, struct nfscllockowner *lp,
4457 uint8_t *fh, int fhlen, struct ucred *cred, NFSPROC_T *p)
4459 struct nfsrv_descript nfsd, *nd = &nfsd;
4462 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
4463 struct nfsclsession *tsep;
4465 if (NFSHASNFSV4N(nmp)) {
4466 /* For NFSv4.1, do a FreeStateID. */
4467 nfscl_reqstart(nd, NFSPROC_FREESTATEID, nmp, NULL, 0, NULL,
4469 nfsm_stateidtom(nd, &lp->nfsl_stateid, NFSSTATEID_PUTSTATEID);
4471 nfscl_reqstart(nd, NFSPROC_RELEASELCKOWN, nmp, NULL, 0, NULL,
4473 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4474 tsep = nfsmnt_mdssession(nmp);
4475 *tl++ = tsep->nfsess_clientid.lval[0];
4476 *tl = tsep->nfsess_clientid.lval[1];
4477 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN);
4478 NFSBCOPY(fh, &own[NFSV4CL_LOCKNAMELEN], fhlen);
4479 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen);
4481 nd->nd_flag |= ND_USEGSSNAME;
4482 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4483 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4486 error = nd->nd_repstat;
4487 mbuf_freem(nd->nd_mrep);
4492 * This function performs the Compound to get the mount pt FH.
4495 nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred,
4499 struct nfsrv_descript nfsd;
4500 struct nfsrv_descript *nd = &nfsd;
4502 int error, cnt, len, setnil;
4505 nfscl_reqstart(nd, NFSPROC_PUTROOTFH, nmp, NULL, 0, &opcntp, NULL, 0,
4514 while (*cp2 != '\0' && *cp2 != '/')
4521 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4522 *tl = txdr_unsigned(NFSV4OP_LOOKUP);
4523 nfsm_strtom(nd, cp, strlen(cp));
4529 } while (*cp != '\0');
4530 if (NFSHASNFSV4N(nmp))
4531 /* Has a Sequence Op done by nfscl_reqstart(). */
4532 *opcntp = txdr_unsigned(3 + cnt);
4534 *opcntp = txdr_unsigned(2 + cnt);
4535 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4536 *tl = txdr_unsigned(NFSV4OP_GETFH);
4537 nd->nd_flag |= ND_USEGSSNAME;
4538 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4539 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4542 if (nd->nd_repstat == 0) {
4543 NFSM_DISSECT(tl, u_int32_t *, (3 + 2 * cnt) * NFSX_UNSIGNED);
4544 tl += (2 + 2 * cnt);
4545 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
4547 nd->nd_repstat = NFSERR_BADXDR;
4549 nd->nd_repstat = nfsrv_mtostr(nd, nmp->nm_fh, len);
4550 if (nd->nd_repstat == 0)
4551 nmp->nm_fhsize = len;
4554 error = nd->nd_repstat;
4556 mbuf_freem(nd->nd_mrep);
4561 * This function performs the Delegreturn RPC.
4564 nfsrpc_delegreturn(struct nfscldeleg *dp, struct ucred *cred,
4565 struct nfsmount *nmp, NFSPROC_T *p, int syscred)
4568 struct nfsrv_descript nfsd;
4569 struct nfsrv_descript *nd = &nfsd;
4572 nfscl_reqstart(nd, NFSPROC_DELEGRETURN, nmp, dp->nfsdl_fh,
4573 dp->nfsdl_fhlen, NULL, NULL, 0, 0);
4574 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
4575 if (NFSHASNFSV4N(nmp))
4578 *tl++ = dp->nfsdl_stateid.seqid;
4579 *tl++ = dp->nfsdl_stateid.other[0];
4580 *tl++ = dp->nfsdl_stateid.other[1];
4581 *tl = dp->nfsdl_stateid.other[2];
4583 nd->nd_flag |= ND_USEGSSNAME;
4584 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4585 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4588 error = nd->nd_repstat;
4589 mbuf_freem(nd->nd_mrep);
4597 nfsrpc_getacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
4598 struct acl *aclp, void *stuff)
4600 struct nfsrv_descript nfsd, *nd = &nfsd;
4602 nfsattrbit_t attrbits;
4603 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
4605 if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp))
4606 return (EOPNOTSUPP);
4607 NFSCL_REQSTART(nd, NFSPROC_GETACL, vp);
4608 NFSZERO_ATTRBIT(&attrbits);
4609 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
4610 (void) nfsrv_putattrbit(nd, &attrbits);
4611 error = nfscl_request(nd, vp, p, cred, stuff);
4614 if (!nd->nd_repstat)
4615 error = nfsv4_loadattr(nd, vp, NULL, NULL, NULL, 0, NULL,
4616 NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, p, cred);
4618 error = nd->nd_repstat;
4619 mbuf_freem(nd->nd_mrep);
4627 nfsrpc_setacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
4628 struct acl *aclp, void *stuff)
4631 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
4633 if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp))
4634 return (EOPNOTSUPP);
4635 error = nfsrpc_setattr(vp, NULL, aclp, cred, p, NULL, NULL, stuff);
4643 nfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
4644 struct acl *aclp, nfsv4stateid_t *stateidp, void *stuff)
4646 struct nfsrv_descript nfsd, *nd = &nfsd;
4648 nfsattrbit_t attrbits;
4649 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
4651 if (!NFSHASNFSV4(nmp))
4652 return (EOPNOTSUPP);
4653 NFSCL_REQSTART(nd, NFSPROC_SETACL, vp);
4654 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
4655 NFSZERO_ATTRBIT(&attrbits);
4656 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
4657 (void) nfsv4_fillattr(nd, vnode_mount(vp), vp, aclp, NULL, NULL, 0,
4658 &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL);
4659 error = nfscl_request(nd, vp, p, cred, stuff);
4662 /* Don't care about the pre/postop attributes */
4663 mbuf_freem(nd->nd_mrep);
4664 return (nd->nd_repstat);
4668 * Do the NFSv4.1 Exchange ID.
4671 nfsrpc_exchangeid(struct nfsmount *nmp, struct nfsclclient *clp,
4672 struct nfssockreq *nrp, int minorvers, uint32_t exchflags,
4673 struct nfsclds **dspp, struct ucred *cred, NFSPROC_T *p)
4675 uint32_t *tl, v41flags;
4676 struct nfsrv_descript nfsd;
4677 struct nfsrv_descript *nd = &nfsd;
4678 struct nfsclds *dsp;
4679 struct timespec verstime;
4684 minorvers = nmp->nm_minorvers;
4685 nfscl_reqstart(nd, NFSPROC_EXCHANGEID, nmp, NULL, 0, NULL, NULL,
4686 NFS_VER4, minorvers);
4687 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4688 *tl++ = txdr_unsigned(nfsboottime.tv_sec); /* Client owner */
4689 *tl = txdr_unsigned(clp->nfsc_rev);
4690 (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen);
4692 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
4693 *tl++ = txdr_unsigned(exchflags);
4694 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE);
4696 /* Set the implementation id4 */
4697 *tl = txdr_unsigned(1);
4698 (void) nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
4699 (void) nfsm_strtom(nd, version, strlen(version));
4700 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
4701 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */
4702 verstime.tv_nsec = 0;
4703 txdr_nfsv4time(&verstime, tl);
4704 nd->nd_flag |= ND_USEGSSNAME;
4705 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
4706 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4707 NFSCL_DEBUG(1, "exchangeid err=%d reps=%d\n", error,
4708 (int)nd->nd_repstat);
4711 if (nd->nd_repstat == 0) {
4712 NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_UNSIGNED + NFSX_HYPER);
4713 len = fxdr_unsigned(int, *(tl + 7));
4714 if (len < 0 || len > NFSV4_OPAQUELIMIT) {
4715 error = NFSERR_BADXDR;
4718 dsp = malloc(sizeof(struct nfsclds) + len + 1, M_NFSCLDS,
4720 dsp->nfsclds_expire = NFSD_MONOSEC + clp->nfsc_renew;
4721 dsp->nfsclds_servownlen = len;
4722 dsp->nfsclds_sess.nfsess_clientid.lval[0] = *tl++;
4723 dsp->nfsclds_sess.nfsess_clientid.lval[1] = *tl++;
4724 dsp->nfsclds_sess.nfsess_sequenceid =
4725 fxdr_unsigned(uint32_t, *tl++);
4726 v41flags = fxdr_unsigned(uint32_t, *tl);
4727 if ((v41flags & NFSV4EXCH_USEPNFSMDS) != 0 &&
4728 NFSHASPNFSOPT(nmp)) {
4729 NFSCL_DEBUG(1, "set PNFS\n");
4731 nmp->nm_state |= NFSSTA_PNFS;
4733 dsp->nfsclds_flags |= NFSCLDS_MDS;
4735 if ((v41flags & NFSV4EXCH_USEPNFSDS) != 0)
4736 dsp->nfsclds_flags |= NFSCLDS_DS;
4737 if (minorvers == NFSV42_MINORVERSION)
4738 dsp->nfsclds_flags |= NFSCLDS_MINORV2;
4740 nd->nd_repstat = nfsrv_mtostr(nd,
4741 dsp->nfsclds_serverown, len);
4742 if (nd->nd_repstat == 0) {
4743 mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF);
4744 mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession",
4746 nfscl_initsessionslots(&dsp->nfsclds_sess);
4749 free(dsp, M_NFSCLDS);
4751 error = nd->nd_repstat;
4753 mbuf_freem(nd->nd_mrep);
4758 * Do the NFSv4.1 Create Session.
4761 nfsrpc_createsession(struct nfsmount *nmp, struct nfsclsession *sep,
4762 struct nfssockreq *nrp, struct nfsclds *dsp, uint32_t sequenceid, int mds,
4763 struct ucred *cred, NFSPROC_T *p)
4765 uint32_t crflags, maxval, *tl;
4766 struct nfsrv_descript nfsd;
4767 struct nfsrv_descript *nd = &nfsd;
4768 int error, irdcnt, minorvers;
4770 /* Make sure nm_rsize, nm_wsize is set. */
4771 if (nmp->nm_rsize > NFS_MAXBSIZE || nmp->nm_rsize == 0)
4772 nmp->nm_rsize = NFS_MAXBSIZE;
4773 if (nmp->nm_wsize > NFS_MAXBSIZE || nmp->nm_wsize == 0)
4774 nmp->nm_wsize = NFS_MAXBSIZE;
4776 minorvers = nmp->nm_minorvers;
4777 else if ((dsp->nfsclds_flags & NFSCLDS_MINORV2) != 0)
4778 minorvers = NFSV42_MINORVERSION;
4780 minorvers = NFSV41_MINORVERSION;
4781 nfscl_reqstart(nd, NFSPROC_CREATESESSION, nmp, NULL, 0, NULL, NULL,
4782 NFS_VER4, minorvers);
4783 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4784 *tl++ = sep->nfsess_clientid.lval[0];
4785 *tl++ = sep->nfsess_clientid.lval[1];
4786 *tl++ = txdr_unsigned(sequenceid);
4787 crflags = (NFSMNT_RDONLY(nmp->nm_mountp) ? 0 : NFSV4CRSESS_PERSIST);
4788 if (nfscl_enablecallb != 0 && nfs_numnfscbd > 0 && mds != 0)
4789 crflags |= NFSV4CRSESS_CONNBACKCHAN;
4790 *tl = txdr_unsigned(crflags);
4792 /* Fill in fore channel attributes. */
4793 NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4794 *tl++ = 0; /* Header pad size */
4795 if ((nd->nd_flag & ND_NFSV42) != 0 && mds != 0 && sb_max_adj >=
4796 nmp->nm_wsize && sb_max_adj >= nmp->nm_rsize) {
4798 * NFSv4.2 Extended Attribute operations may want to do
4799 * requests/replies that are larger than nm_rsize/nm_wsize.
4801 *tl++ = txdr_unsigned(sb_max_adj - NFS_MAXXDR);
4802 *tl++ = txdr_unsigned(sb_max_adj - NFS_MAXXDR);
4804 *tl++ = txdr_unsigned(nmp->nm_wsize + NFS_MAXXDR);
4805 *tl++ = txdr_unsigned(nmp->nm_rsize + NFS_MAXXDR);
4807 *tl++ = txdr_unsigned(4096); /* Max response size cached */
4808 *tl++ = txdr_unsigned(20); /* Max operations */
4809 *tl++ = txdr_unsigned(64); /* Max slots */
4810 *tl = 0; /* No rdma ird */
4812 /* Fill in back channel attributes. */
4813 NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4814 *tl++ = 0; /* Header pad size */
4815 *tl++ = txdr_unsigned(10000); /* Max request size */
4816 *tl++ = txdr_unsigned(10000); /* Max response size */
4817 *tl++ = txdr_unsigned(4096); /* Max response size cached */
4818 *tl++ = txdr_unsigned(4); /* Max operations */
4819 *tl++ = txdr_unsigned(NFSV4_CBSLOTS); /* Max slots */
4820 *tl = 0; /* No rdma ird */
4822 NFSM_BUILD(tl, uint32_t *, 8 * NFSX_UNSIGNED);
4823 *tl++ = txdr_unsigned(NFS_CALLBCKPROG); /* Call back prog # */
4825 /* Allow AUTH_SYS callbacks as uid, gid == 0. */
4826 *tl++ = txdr_unsigned(1); /* Auth_sys only */
4827 *tl++ = txdr_unsigned(AUTH_SYS); /* AUTH_SYS type */
4828 *tl++ = txdr_unsigned(nfsboottime.tv_sec); /* time stamp */
4829 *tl++ = 0; /* Null machine name */
4830 *tl++ = 0; /* Uid == 0 */
4831 *tl++ = 0; /* Gid == 0 */
4832 *tl = 0; /* No additional gids */
4833 nd->nd_flag |= ND_USEGSSNAME;
4834 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, NFS_PROG,
4835 NFS_VER4, NULL, 1, NULL, NULL);
4838 if (nd->nd_repstat == 0) {
4839 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID +
4841 bcopy(tl, sep->nfsess_sessionid, NFSX_V4SESSIONID);
4842 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4843 sep->nfsess_sequenceid = fxdr_unsigned(uint32_t, *tl++);
4844 crflags = fxdr_unsigned(uint32_t, *tl);
4845 if ((crflags & NFSV4CRSESS_PERSIST) != 0 && mds != 0) {
4847 nmp->nm_state |= NFSSTA_SESSPERSIST;
4851 /* Get the fore channel slot count. */
4852 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4853 tl++; /* Skip the header pad size. */
4855 /* Make sure nm_wsize is small enough. */
4856 maxval = fxdr_unsigned(uint32_t, *tl++);
4857 while (maxval < nmp->nm_wsize + NFS_MAXXDR) {
4858 if (nmp->nm_wsize > 8096)
4863 sep->nfsess_maxreq = maxval;
4865 /* Make sure nm_rsize is small enough. */
4866 maxval = fxdr_unsigned(uint32_t, *tl++);
4867 while (maxval < nmp->nm_rsize + NFS_MAXXDR) {
4868 if (nmp->nm_rsize > 8096)
4873 sep->nfsess_maxresp = maxval;
4875 sep->nfsess_maxcache = fxdr_unsigned(int, *tl++);
4877 sep->nfsess_foreslots = fxdr_unsigned(uint16_t, *tl++);
4878 NFSCL_DEBUG(4, "fore slots=%d\n", (int)sep->nfsess_foreslots);
4879 irdcnt = fxdr_unsigned(int, *tl);
4881 NFSM_DISSECT(tl, uint32_t *, irdcnt * NFSX_UNSIGNED);
4883 /* and the back channel slot count. */
4884 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4886 sep->nfsess_backslots = fxdr_unsigned(uint16_t, *tl);
4887 NFSCL_DEBUG(4, "back slots=%d\n", (int)sep->nfsess_backslots);
4889 error = nd->nd_repstat;
4891 mbuf_freem(nd->nd_mrep);
4896 * Do the NFSv4.1 Destroy Session.
4899 nfsrpc_destroysession(struct nfsmount *nmp, struct nfsclclient *clp,
4900 struct ucred *cred, NFSPROC_T *p)
4903 struct nfsrv_descript nfsd;
4904 struct nfsrv_descript *nd = &nfsd;
4906 struct nfsclsession *tsep;
4908 nfscl_reqstart(nd, NFSPROC_DESTROYSESSION, nmp, NULL, 0, NULL, NULL, 0,
4910 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4911 tsep = nfsmnt_mdssession(nmp);
4912 bcopy(tsep->nfsess_sessionid, tl, NFSX_V4SESSIONID);
4913 nd->nd_flag |= ND_USEGSSNAME;
4914 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4915 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4918 error = nd->nd_repstat;
4919 mbuf_freem(nd->nd_mrep);
4924 * Do the NFSv4.1 Destroy Client.
4927 nfsrpc_destroyclient(struct nfsmount *nmp, struct nfsclclient *clp,
4928 struct ucred *cred, NFSPROC_T *p)
4931 struct nfsrv_descript nfsd;
4932 struct nfsrv_descript *nd = &nfsd;
4934 struct nfsclsession *tsep;
4936 nfscl_reqstart(nd, NFSPROC_DESTROYCLIENT, nmp, NULL, 0, NULL, NULL, 0,
4938 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4939 tsep = nfsmnt_mdssession(nmp);
4940 *tl++ = tsep->nfsess_clientid.lval[0];
4941 *tl = tsep->nfsess_clientid.lval[1];
4942 nd->nd_flag |= ND_USEGSSNAME;
4943 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4944 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4947 error = nd->nd_repstat;
4948 mbuf_freem(nd->nd_mrep);
4953 * Do the NFSv4.1 LayoutGet.
4956 nfsrpc_layoutget(struct nfsmount *nmp, uint8_t *fhp, int fhlen, int iomode,
4957 uint64_t offset, uint64_t len, uint64_t minlen, int layouttype,
4958 int layoutlen, nfsv4stateid_t *stateidp, int *retonclosep,
4959 struct nfsclflayouthead *flhp, struct ucred *cred, NFSPROC_T *p,
4962 struct nfsrv_descript nfsd, *nd = &nfsd;
4965 nfscl_reqstart(nd, NFSPROC_LAYOUTGET, nmp, fhp, fhlen, NULL, NULL, 0,
4967 nfsrv_setuplayoutget(nd, iomode, offset, len, minlen, stateidp,
4968 layouttype, layoutlen, 0);
4969 nd->nd_flag |= ND_USEGSSNAME;
4970 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4971 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4972 NFSCL_DEBUG(4, "layget err=%d st=%d\n", error, nd->nd_repstat);
4975 if (nd->nd_repstat == 0)
4976 error = nfsrv_parselayoutget(nmp, nd, stateidp, retonclosep,
4978 if (error == 0 && nd->nd_repstat != 0)
4979 error = nd->nd_repstat;
4980 mbuf_freem(nd->nd_mrep);
4985 * Do the NFSv4.1 Get Device Info.
4988 nfsrpc_getdeviceinfo(struct nfsmount *nmp, uint8_t *deviceid, int layouttype,
4989 uint32_t *notifybitsp, struct nfscldevinfo **ndip, struct ucred *cred,
4992 uint32_t cnt, *tl, vers, minorvers;
4993 struct nfsrv_descript nfsd;
4994 struct nfsrv_descript *nd = &nfsd;
4995 struct sockaddr_in sin, ssin;
4996 struct sockaddr_in6 sin6, ssin6;
4997 struct nfsclds *dsp = NULL, **dspp, **gotdspp;
4998 struct nfscldevinfo *ndi;
4999 int addrcnt = 0, bitcnt, error, gotminor, gotvers, i, isudp, j;
5001 uint8_t stripeindex;
5002 sa_family_t af, safilled;
5004 ssin.sin_port = 0; /* To shut up compiler. */
5005 ssin.sin_addr.s_addr = 0; /* ditto */
5009 nfscl_reqstart(nd, NFSPROC_GETDEVICEINFO, nmp, NULL, 0, NULL, NULL, 0,
5011 NFSM_BUILD(tl, uint32_t *, NFSX_V4DEVICEID + 3 * NFSX_UNSIGNED);
5012 NFSBCOPY(deviceid, tl, NFSX_V4DEVICEID);
5013 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5014 *tl++ = txdr_unsigned(layouttype);
5015 *tl++ = txdr_unsigned(100000);
5016 if (notifybitsp != NULL && *notifybitsp != 0) {
5017 *tl = txdr_unsigned(1); /* One word of bits. */
5018 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5019 *tl = txdr_unsigned(*notifybitsp);
5021 *tl = txdr_unsigned(0);
5022 nd->nd_flag |= ND_USEGSSNAME;
5023 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5024 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5027 if (nd->nd_repstat == 0) {
5028 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
5029 if (layouttype != fxdr_unsigned(int, *tl))
5030 printf("EEK! devinfo layout type not same!\n");
5031 if (layouttype == NFSLAYOUT_NFSV4_1_FILES) {
5032 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5033 stripecnt = fxdr_unsigned(int, *tl);
5034 NFSCL_DEBUG(4, "stripecnt=%d\n", stripecnt);
5035 if (stripecnt < 1 || stripecnt > 4096) {
5036 printf("pNFS File layout devinfo stripecnt %d:"
5037 " out of range\n", stripecnt);
5038 error = NFSERR_BADXDR;
5041 NFSM_DISSECT(tl, uint32_t *, (stripecnt + 1) *
5043 addrcnt = fxdr_unsigned(int, *(tl + stripecnt));
5044 NFSCL_DEBUG(4, "addrcnt=%d\n", addrcnt);
5045 if (addrcnt < 1 || addrcnt > 128) {
5046 printf("NFS devinfo addrcnt %d: out of range\n",
5048 error = NFSERR_BADXDR;
5053 * Now we know how many stripe indices and addresses, so
5054 * we can allocate the structure the correct size.
5056 i = (stripecnt * sizeof(uint8_t)) /
5057 sizeof(struct nfsclds *) + 1;
5058 NFSCL_DEBUG(4, "stripeindices=%d\n", i);
5059 ndi = malloc(sizeof(*ndi) + (addrcnt + i) *
5060 sizeof(struct nfsclds *), M_NFSDEVINFO, M_WAITOK |
5062 NFSBCOPY(deviceid, ndi->nfsdi_deviceid,
5064 ndi->nfsdi_refcnt = 0;
5065 ndi->nfsdi_flags = NFSDI_FILELAYOUT;
5066 ndi->nfsdi_stripecnt = stripecnt;
5067 ndi->nfsdi_addrcnt = addrcnt;
5068 /* Fill in the stripe indices. */
5069 for (i = 0; i < stripecnt; i++) {
5070 stripeindex = fxdr_unsigned(uint8_t, *tl++);
5071 NFSCL_DEBUG(4, "stripeind=%d\n", stripeindex);
5072 if (stripeindex >= addrcnt) {
5073 printf("pNFS File Layout devinfo"
5074 " stripeindex %d: too big\n",
5076 error = NFSERR_BADXDR;
5079 nfsfldi_setstripeindex(ndi, i, stripeindex);
5081 } else if (layouttype == NFSLAYOUT_FLEXFILE) {
5082 /* For Flex File, we only get one address list. */
5083 ndi = malloc(sizeof(*ndi) + sizeof(struct nfsclds *),
5084 M_NFSDEVINFO, M_WAITOK | M_ZERO);
5085 NFSBCOPY(deviceid, ndi->nfsdi_deviceid,
5087 ndi->nfsdi_refcnt = 0;
5088 ndi->nfsdi_flags = NFSDI_FLEXFILE;
5089 addrcnt = ndi->nfsdi_addrcnt = 1;
5092 /* Now, dissect the server address(es). */
5093 safilled = AF_UNSPEC;
5094 for (i = 0; i < addrcnt; i++) {
5095 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5096 cnt = fxdr_unsigned(uint32_t, *tl);
5098 printf("NFS devinfo 0 len addrlist\n");
5099 error = NFSERR_BADXDR;
5102 dspp = nfsfldi_addr(ndi, i);
5103 safilled = AF_UNSPEC;
5104 for (j = 0; j < cnt; j++) {
5105 error = nfsv4_getipaddr(nd, &sin, &sin6, &af,
5107 if (error != 0 && error != EPERM) {
5108 error = NFSERR_BADXDR;
5111 if (error == 0 && isudp == 0) {
5114 * - Same address family.
5115 * Save the address and dspp, so that
5116 * the connection can be done after
5117 * parsing is complete.
5119 if (safilled == AF_UNSPEC ||
5120 (af == nmp->nm_nam->sa_family &&
5121 safilled != nmp->nm_nam->sa_family)
5134 gotvers = NFS_VER4; /* Default NFSv4.1 for File Layout. */
5135 gotminor = NFSV41_MINORVERSION;
5136 /* For Flex File, we will take one of the versions to use. */
5137 if (layouttype == NFSLAYOUT_FLEXFILE) {
5138 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5139 j = fxdr_unsigned(int, *tl);
5140 if (j < 1 || j > NFSDEV_MAXVERS) {
5141 printf("pNFS: too many versions\n");
5142 error = NFSERR_BADXDR;
5147 for (i = 0; i < j; i++) {
5148 NFSM_DISSECT(tl, uint32_t *, 5 * NFSX_UNSIGNED);
5149 vers = fxdr_unsigned(uint32_t, *tl++);
5150 minorvers = fxdr_unsigned(uint32_t, *tl++);
5151 if (vers == NFS_VER3)
5153 if ((vers == NFS_VER4 && ((minorvers ==
5154 NFSV41_MINORVERSION && gotminor == 0) ||
5155 minorvers == NFSV42_MINORVERSION)) ||
5156 (vers == NFS_VER3 && gotvers == 0)) {
5158 gotminor = minorvers;
5159 /* We'll take this one. */
5160 ndi->nfsdi_versindex = i;
5161 ndi->nfsdi_vers = vers;
5162 ndi->nfsdi_minorvers = minorvers;
5163 ndi->nfsdi_rsize = fxdr_unsigned(
5165 ndi->nfsdi_wsize = fxdr_unsigned(
5167 if (*tl == newnfs_true)
5172 ~NFSDI_TIGHTCOUPLED;
5176 printf("pNFS: no NFSv3, NFSv4.1 or NFSv4.2\n");
5177 error = NFSERR_BADXDR;
5182 /* And the notify bits. */
5183 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5184 bitcnt = fxdr_unsigned(int, *tl);
5186 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5187 if (notifybitsp != NULL)
5189 fxdr_unsigned(uint32_t, *tl);
5191 if (safilled != AF_UNSPEC) {
5192 KASSERT(ndi != NULL, ("ndi is NULL"));
5198 * Now we can do a TCP connection for the correct
5199 * NFS version and IP address.
5201 error = nfsrpc_fillsa(nmp, &ssin, &ssin6, safilled,
5202 gotvers, gotminor, &dsp, p);
5205 KASSERT(gotdspp != NULL, ("gotdspp is NULL"));
5209 if (nd->nd_repstat != 0 && error == 0)
5210 error = nd->nd_repstat;
5212 if (error != 0 && ndi != NULL)
5213 nfscl_freedevinfo(ndi);
5214 mbuf_freem(nd->nd_mrep);
5219 * Do the NFSv4.1 LayoutCommit.
5222 nfsrpc_layoutcommit(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim,
5223 uint64_t off, uint64_t len, uint64_t lastbyte, nfsv4stateid_t *stateidp,
5224 int layouttype, struct ucred *cred, NFSPROC_T *p, void *stuff)
5227 struct nfsrv_descript nfsd, *nd = &nfsd;
5230 nfscl_reqstart(nd, NFSPROC_LAYOUTCOMMIT, nmp, fh, fhlen, NULL, NULL,
5232 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
5234 txdr_hyper(off, tl);
5236 txdr_hyper(len, tl);
5239 *tl++ = newnfs_true;
5241 *tl++ = newnfs_false;
5242 *tl++ = txdr_unsigned(stateidp->seqid);
5243 *tl++ = stateidp->other[0];
5244 *tl++ = stateidp->other[1];
5245 *tl++ = stateidp->other[2];
5246 *tl++ = newnfs_true;
5249 else if (lastbyte >= (off + len))
5250 lastbyte = off + len - 1;
5251 txdr_hyper(lastbyte, tl);
5253 *tl++ = newnfs_false;
5254 *tl++ = txdr_unsigned(layouttype);
5255 /* All supported layouts are 0 length. */
5256 *tl = txdr_unsigned(0);
5257 nd->nd_flag |= ND_USEGSSNAME;
5258 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5259 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5262 error = nd->nd_repstat;
5263 mbuf_freem(nd->nd_mrep);
5268 * Do the NFSv4.1 LayoutReturn.
5271 nfsrpc_layoutreturn(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim,
5272 int layouttype, uint32_t iomode, int layoutreturn, uint64_t offset,
5273 uint64_t len, nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p,
5274 uint32_t stat, uint32_t op, char *devid)
5277 struct nfsrv_descript nfsd, *nd = &nfsd;
5281 nfscl_reqstart(nd, NFSPROC_LAYOUTRETURN, nmp, fh, fhlen, NULL, NULL,
5283 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED);
5285 *tl++ = newnfs_true;
5287 *tl++ = newnfs_false;
5288 *tl++ = txdr_unsigned(layouttype);
5289 *tl++ = txdr_unsigned(iomode);
5290 *tl = txdr_unsigned(layoutreturn);
5291 if (layoutreturn == NFSLAYOUTRETURN_FILE) {
5292 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
5294 txdr_hyper(offset, tl);
5296 txdr_hyper(len, tl);
5298 NFSCL_DEBUG(4, "layoutret stseq=%d\n", (int)stateidp->seqid);
5299 *tl++ = txdr_unsigned(stateidp->seqid);
5300 *tl++ = stateidp->other[0];
5301 *tl++ = stateidp->other[1];
5302 *tl++ = stateidp->other[2];
5303 if (layouttype == NFSLAYOUT_NFSV4_1_FILES)
5304 *tl = txdr_unsigned(0);
5305 else if (layouttype == NFSLAYOUT_FLEXFILE) {
5307 *tl = txdr_unsigned(2 * NFSX_HYPER +
5308 NFSX_STATEID + NFSX_V4DEVICEID + 5 *
5310 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER +
5311 NFSX_STATEID + NFSX_V4DEVICEID + 5 *
5313 *tl++ = txdr_unsigned(1); /* One error. */
5314 tu64 = 0; /* Offset. */
5315 txdr_hyper(tu64, tl); tl += 2;
5316 tu64 = UINT64_MAX; /* Length. */
5317 txdr_hyper(tu64, tl); tl += 2;
5318 NFSBCOPY(stateidp, tl, NFSX_STATEID);
5319 tl += (NFSX_STATEID / NFSX_UNSIGNED);
5320 *tl++ = txdr_unsigned(1); /* One error. */
5321 NFSBCOPY(devid, tl, NFSX_V4DEVICEID);
5322 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5323 *tl++ = txdr_unsigned(stat);
5324 *tl++ = txdr_unsigned(op);
5326 *tl = txdr_unsigned(2 * NFSX_UNSIGNED);
5327 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
5331 *tl = 0; /* No stats yet. */
5334 nd->nd_flag |= ND_USEGSSNAME;
5335 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5336 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5339 if (nd->nd_repstat == 0) {
5340 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5342 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
5343 stateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
5344 stateidp->other[0] = *tl++;
5345 stateidp->other[1] = *tl++;
5346 stateidp->other[2] = *tl;
5349 error = nd->nd_repstat;
5351 mbuf_freem(nd->nd_mrep);
5356 * Acquire a layout and devinfo, if possible. The caller must have acquired
5357 * a reference count on the nfsclclient structure before calling this.
5358 * Return the layout in lypp with a reference count on it, if successful.
5361 nfsrpc_getlayout(struct nfsmount *nmp, vnode_t vp, struct nfsfh *nfhp,
5362 int iomode, uint32_t *notifybitsp, nfsv4stateid_t *stateidp, uint64_t off,
5363 struct nfscllayout **lypp, struct ucred *cred, NFSPROC_T *p)
5365 struct nfscllayout *lyp;
5366 struct nfsclflayout *flp;
5367 struct nfsclflayouthead flh;
5368 int error = 0, islocked, layoutlen, layouttype, recalled, retonclose;
5369 nfsv4stateid_t stateid;
5370 struct nfsclsession *tsep;
5373 if (NFSHASFLEXFILE(nmp))
5374 layouttype = NFSLAYOUT_FLEXFILE;
5376 layouttype = NFSLAYOUT_NFSV4_1_FILES;
5378 * If lyp is returned non-NULL, there will be a refcnt (shared lock)
5379 * on it, iff flp != NULL or a lock (exclusive lock) on it iff
5382 lyp = nfscl_getlayout(nmp->nm_clp, nfhp->nfh_fh, nfhp->nfh_len,
5383 off, &flp, &recalled);
5385 if (lyp == NULL || flp == NULL) {
5389 tsep = nfsmnt_mdssession(nmp);
5390 layoutlen = tsep->nfsess_maxcache -
5391 (NFSX_STATEID + 3 * NFSX_UNSIGNED);
5394 stateid.other[0] = stateidp->other[0];
5395 stateid.other[1] = stateidp->other[1];
5396 stateid.other[2] = stateidp->other[2];
5397 error = nfsrpc_layoutget(nmp, nfhp->nfh_fh,
5398 nfhp->nfh_len, iomode, (uint64_t)0, UINT64_MAX,
5399 (uint64_t)0, layouttype, layoutlen, &stateid,
5400 &retonclose, &flh, cred, p, NULL);
5403 stateid.seqid = lyp->nfsly_stateid.seqid;
5404 stateid.other[0] = lyp->nfsly_stateid.other[0];
5405 stateid.other[1] = lyp->nfsly_stateid.other[1];
5406 stateid.other[2] = lyp->nfsly_stateid.other[2];
5407 error = nfsrpc_layoutget(nmp, nfhp->nfh_fh,
5408 nfhp->nfh_len, iomode, off, UINT64_MAX,
5409 (uint64_t)0, layouttype, layoutlen, &stateid,
5410 &retonclose, &flh, cred, p, NULL);
5412 error = nfsrpc_layoutgetres(nmp, vp, nfhp->nfh_fh,
5413 nfhp->nfh_len, &stateid, retonclose, notifybitsp, &lyp,
5414 &flh, layouttype, error, NULL, cred, p);
5417 else if (islocked != 0)
5418 nfscl_rellayout(lyp, 1);
5425 * Do a TCP connection plus exchange id and create session.
5426 * If successful, a "struct nfsclds" is linked into the list for the
5427 * mount point and a pointer to it is returned.
5430 nfsrpc_fillsa(struct nfsmount *nmp, struct sockaddr_in *sin,
5431 struct sockaddr_in6 *sin6, sa_family_t af, int vers, int minorvers,
5432 struct nfsclds **dspp, NFSPROC_T *p)
5434 struct sockaddr_in *msad, *sad;
5435 struct sockaddr_in6 *msad6, *sad6;
5436 struct nfsclclient *clp;
5437 struct nfssockreq *nrp;
5438 struct nfsclds *dsp, *tdsp;
5439 int error, firsttry;
5440 enum nfsclds_state retv;
5441 uint32_t sequenceid = 0;
5443 KASSERT(nmp->nm_sockreq.nr_cred != NULL,
5444 ("nfsrpc_fillsa: NULL nr_cred"));
5450 if (af == AF_INET) {
5453 * Check to see if we already have a session for this
5454 * address that is usable for a DS.
5455 * Note that the MDS's address is in a different place
5456 * than the sessions already acquired for DS's.
5458 msad = (struct sockaddr_in *)nmp->nm_sockreq.nr_nam;
5459 tdsp = TAILQ_FIRST(&nmp->nm_sess);
5460 while (tdsp != NULL) {
5461 if (msad != NULL && msad->sin_family == AF_INET &&
5462 sin->sin_addr.s_addr == msad->sin_addr.s_addr &&
5463 sin->sin_port == msad->sin_port &&
5464 (tdsp->nfsclds_flags & NFSCLDS_DS) != 0 &&
5465 tdsp->nfsclds_sess.nfsess_defunct == 0) {
5468 NFSCL_DEBUG(4, "fnd same addr\n");
5471 tdsp = TAILQ_NEXT(tdsp, nfsclds_list);
5472 if (tdsp != NULL && tdsp->nfsclds_sockp != NULL)
5473 msad = (struct sockaddr_in *)
5474 tdsp->nfsclds_sockp->nr_nam;
5480 /* No IP address match, so look for new/trunked one. */
5481 sad = malloc(sizeof(*sad), M_SONAME, M_WAITOK | M_ZERO);
5482 sad->sin_len = sizeof(*sad);
5483 sad->sin_family = AF_INET;
5484 sad->sin_port = sin->sin_port;
5485 sad->sin_addr.s_addr = sin->sin_addr.s_addr;
5486 nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO);
5487 nrp->nr_nam = (struct sockaddr *)sad;
5488 } else if (af == AF_INET6) {
5491 * Check to see if we already have a session for this
5492 * address that is usable for a DS.
5493 * Note that the MDS's address is in a different place
5494 * than the sessions already acquired for DS's.
5496 msad6 = (struct sockaddr_in6 *)nmp->nm_sockreq.nr_nam;
5497 tdsp = TAILQ_FIRST(&nmp->nm_sess);
5498 while (tdsp != NULL) {
5499 if (msad6 != NULL && msad6->sin6_family == AF_INET6 &&
5500 IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
5501 &msad6->sin6_addr) &&
5502 sin6->sin6_port == msad6->sin6_port &&
5503 (tdsp->nfsclds_flags & NFSCLDS_DS) != 0 &&
5504 tdsp->nfsclds_sess.nfsess_defunct == 0) {
5509 tdsp = TAILQ_NEXT(tdsp, nfsclds_list);
5510 if (tdsp != NULL && tdsp->nfsclds_sockp != NULL)
5511 msad6 = (struct sockaddr_in6 *)
5512 tdsp->nfsclds_sockp->nr_nam;
5518 /* No IP address match, so look for new/trunked one. */
5519 sad6 = malloc(sizeof(*sad6), M_SONAME, M_WAITOK | M_ZERO);
5520 sad6->sin6_len = sizeof(*sad6);
5521 sad6->sin6_family = AF_INET6;
5522 sad6->sin6_port = sin6->sin6_port;
5523 NFSBCOPY(&sin6->sin6_addr, &sad6->sin6_addr,
5524 sizeof(struct in6_addr));
5525 nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO);
5526 nrp->nr_nam = (struct sockaddr *)sad6;
5530 nrp->nr_sotype = SOCK_STREAM;
5531 mtx_init(&nrp->nr_mtx, "nfssock", NULL, MTX_DEF);
5532 nrp->nr_prog = NFS_PROG;
5533 nrp->nr_vers = vers;
5536 * Use the credentials that were used for the mount, which are
5537 * in nmp->nm_sockreq.nr_cred for newnfs_connect() etc.
5538 * Ref. counting the credentials with crhold() is probably not
5539 * necessary, since nm_sockreq.nr_cred won't be crfree()'d until
5540 * unmount, but I did it anyhow.
5542 nrp->nr_cred = crhold(nmp->nm_sockreq.nr_cred);
5543 error = newnfs_connect(nmp, nrp, NULL, p, 0);
5544 NFSCL_DEBUG(3, "DS connect=%d\n", error);
5547 /* Now, do the exchangeid and create session. */
5549 if (vers == NFS_VER4) {
5552 error = nfsrpc_exchangeid(nmp, clp, nrp,
5553 minorvers, NFSV4EXCH_USEPNFSDS, &dsp,
5555 NFSCL_DEBUG(3, "DS exchangeid=%d\n", error);
5556 if (error == NFSERR_MINORVERMISMATCH)
5557 minorvers = NFSV42_MINORVERSION;
5558 } while (error == NFSERR_MINORVERMISMATCH &&
5561 newnfs_disconnect(nrp);
5563 dsp = malloc(sizeof(struct nfsclds), M_NFSCLDS,
5565 dsp->nfsclds_flags |= NFSCLDS_DS;
5566 dsp->nfsclds_expire = INT32_MAX; /* No renews needed. */
5567 mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF);
5568 mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession",
5573 dsp->nfsclds_sockp = nrp;
5574 if (vers == NFS_VER4) {
5576 retv = nfscl_getsameserver(nmp, dsp, &tdsp,
5578 NFSCL_DEBUG(3, "getsame ret=%d\n", retv);
5579 if (retv == NFSDSP_USETHISSESSION &&
5580 nfscl_dssameconn != 0) {
5582 tdsp->nfsclds_flags |= NFSCLDS_SAMECONN;
5586 * If there is already a session for this
5589 (void)newnfs_disconnect(nrp);
5590 nfscl_freenfsclds(dsp);
5594 if (retv == NFSDSP_NOTFOUND)
5596 dsp->nfsclds_sess.nfsess_sequenceid;
5598 error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess,
5599 nrp, dsp, sequenceid, 0, nrp->nr_cred, p);
5600 NFSCL_DEBUG(3, "DS createsess=%d\n", error);
5603 NFSFREECRED(nrp->nr_cred);
5604 NFSFREEMUTEX(&nrp->nr_mtx);
5605 free(nrp->nr_nam, M_SONAME);
5606 free(nrp, M_NFSSOCKREQ);
5609 NFSCL_DEBUG(3, "add DS session\n");
5611 * Put it at the end of the list. That way the list
5612 * is ordered by when the entry was added. This matters
5613 * since the one done first is the one that should be
5614 * used for sequencid'ing any subsequent create sessions.
5617 TAILQ_INSERT_TAIL(&nmp->nm_sess, dsp, nfsclds_list);
5620 } else if (dsp != NULL) {
5621 newnfs_disconnect(nrp);
5622 nfscl_freenfsclds(dsp);
5628 * Do the NFSv4.1 Reclaim Complete.
5631 nfsrpc_reclaimcomplete(struct nfsmount *nmp, struct ucred *cred, NFSPROC_T *p)
5634 struct nfsrv_descript nfsd;
5635 struct nfsrv_descript *nd = &nfsd;
5638 nfscl_reqstart(nd, NFSPROC_RECLAIMCOMPL, nmp, NULL, 0, NULL, NULL, 0,
5640 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5642 nd->nd_flag |= ND_USEGSSNAME;
5643 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5644 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5647 error = nd->nd_repstat;
5648 mbuf_freem(nd->nd_mrep);
5653 * Initialize the slot tables for a session.
5656 nfscl_initsessionslots(struct nfsclsession *sep)
5660 for (i = 0; i < NFSV4_CBSLOTS; i++) {
5661 if (sep->nfsess_cbslots[i].nfssl_reply != NULL)
5662 m_freem(sep->nfsess_cbslots[i].nfssl_reply);
5663 NFSBZERO(&sep->nfsess_cbslots[i], sizeof(struct nfsslot));
5665 for (i = 0; i < 64; i++)
5666 sep->nfsess_slotseq[i] = 0;
5667 sep->nfsess_slots = 0;
5671 * Called to try and do an I/O operation via an NFSv4.1 Data Server (DS).
5674 nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
5675 uint32_t rwaccess, int docommit, struct ucred *cred, NFSPROC_T *p)
5677 struct nfsnode *np = VTONFS(vp);
5678 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
5679 struct nfscllayout *layp;
5680 struct nfscldevinfo *dip;
5681 struct nfsclflayout *rflp;
5683 struct nfsclwritedsdorpc *drpc, *tdrpc;
5684 nfsv4stateid_t stateid;
5685 struct ucred *newcred;
5686 uint64_t lastbyte, len, off, oresid, xfer;
5687 int eof, error, firstmirror, i, iolaymode, mirrorcnt, recalled, timo;
5690 void *iovbase = NULL;
5695 if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || nfs_numnfscbd == 0 ||
5696 (np->n_flag & NNOLAYOUT) != 0)
5698 /* Now, get a reference cnt on the clientid for this mount. */
5699 if (nfscl_getref(nmp) == 0)
5702 /* Find an appropriate stateid. */
5703 newcred = NFSNEWCRED(cred);
5704 error = nfscl_getstateid(vp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len,
5705 rwaccess, 1, newcred, p, &stateid, &lckp);
5707 NFSFREECRED(newcred);
5711 /* Search for a layout for this file. */
5712 off = uiop->uio_offset;
5713 layp = nfscl_getlayout(nmp->nm_clp, np->n_fhp->nfh_fh,
5714 np->n_fhp->nfh_len, off, &rflp, &recalled);
5715 if (layp == NULL || rflp == NULL) {
5716 if (recalled != 0) {
5717 NFSFREECRED(newcred);
5722 nfscl_rellayout(layp, (rflp == NULL) ? 1 : 0);
5725 /* Try and get a Layout, if it is supported. */
5726 if (rwaccess == NFSV4OPEN_ACCESSWRITE ||
5727 (np->n_flag & NWRITEOPENED) != 0)
5728 iolaymode = NFSLAYOUTIOMODE_RW;
5730 iolaymode = NFSLAYOUTIOMODE_READ;
5731 error = nfsrpc_getlayout(nmp, vp, np->n_fhp, iolaymode,
5732 NULL, &stateid, off, &layp, newcred, p);
5735 np->n_flag |= NNOLAYOUT;
5738 nfscl_lockderef(lckp);
5739 NFSFREECRED(newcred);
5741 nfscl_rellayout(layp, 0);
5748 * Loop around finding a layout that works for the first part of
5749 * this I/O operation, and then call the function that actually
5753 len = (uint64_t)uiop->uio_resid;
5754 while (len > 0 && error == 0 && eof == 0) {
5755 off = uiop->uio_offset;
5756 error = nfscl_findlayoutforio(layp, off, rwaccess, &rflp);
5758 oresid = xfer = (uint64_t)uiop->uio_resid;
5759 if (xfer > (rflp->nfsfl_end - rflp->nfsfl_off))
5760 xfer = rflp->nfsfl_end - rflp->nfsfl_off;
5762 * For Flex File layout with mirrored DSs, select one
5763 * of them at random for reads. For writes and commits,
5767 tdrpc = drpc = NULL;
5770 if ((layp->nfsly_flags & NFSLY_FLEXFILE) != 0 &&
5771 (mirrorcnt = rflp->nfsfl_mirrorcnt) > 1) {
5772 if (rwaccess == NFSV4OPEN_ACCESSREAD) {
5773 firstmirror = arc4random() % mirrorcnt;
5774 mirrorcnt = firstmirror + 1;
5776 if (docommit == 0) {
5778 * Save values, so uiop can be
5779 * rolled back upon a write
5782 offs = uiop->uio_offset;
5783 resid = uiop->uio_resid;
5785 uiop->uio_iov->iov_base;
5786 iovlen = uiop->uio_iov->iov_len;
5787 m = nfsm_uiombuflist(uiop, len,
5790 tdrpc = drpc = malloc(sizeof(*drpc) *
5791 (mirrorcnt - 1), M_TEMP, M_WAITOK |
5795 for (i = firstmirror; i < mirrorcnt && error == 0; i++){
5796 if ((layp->nfsly_flags & NFSLY_FLEXFILE) != 0) {
5797 dev = rflp->nfsfl_ffm[i].dev;
5798 dip = nfscl_getdevinfo(nmp->nm_clp, dev,
5799 rflp->nfsfl_ffm[i].devp);
5801 dev = rflp->nfsfl_dev;
5802 dip = nfscl_getdevinfo(nmp->nm_clp, dev,
5806 if ((rflp->nfsfl_flags & NFSFL_FLEXFILE)
5808 error = nfscl_dofflayoutio(vp,
5809 uiop, iomode, must_commit,
5810 &eof, &stateid, rwaccess,
5811 dip, layp, rflp, off, xfer,
5812 i, docommit, m, tdrpc,
5815 error = nfscl_doflayoutio(vp,
5816 uiop, iomode, must_commit,
5817 &eof, &stateid, rwaccess,
5818 dip, layp, rflp, off, xfer,
5819 docommit, newcred, p);
5820 nfscl_reldevinfo(dip);
5828 timo = hz / 50; /* Wait for 20msec. */
5831 for (i = firstmirror; i < mirrorcnt - 1 &&
5832 tdrpc != NULL; i++, tdrpc++) {
5834 * For the unused drpc entries, both inprog and
5835 * err == 0, so this loop won't break.
5837 while (tdrpc->inprog != 0 && tdrpc->done == 0)
5838 tsleep(&tdrpc->tsk, PVFS, "clrpcio",
5840 if (error == 0 && tdrpc->err != 0)
5845 if (mirrorcnt > 1 && rwaccess ==
5846 NFSV4OPEN_ACCESSWRITE && docommit == 0) {
5848 layp->nfsly_flags |= NFSLY_WRITTEN;
5851 lastbyte = off + xfer - 1;
5853 if (lastbyte > layp->nfsly_lastbyte)
5854 layp->nfsly_lastbyte = lastbyte;
5856 } else if (error == NFSERR_OPENMODE &&
5857 rwaccess == NFSV4OPEN_ACCESSREAD) {
5859 nmp->nm_state |= NFSSTA_OPENMODE;
5864 len -= (oresid - (uint64_t)uiop->uio_resid);
5865 else if (mirrorcnt > 1 && rwaccess ==
5866 NFSV4OPEN_ACCESSWRITE && docommit == 0) {
5868 * In case the rpc gets retried, roll the
5869 * uio fields changed by nfsm_uiombuflist()
5872 uiop->uio_offset = offs;
5873 uiop->uio_resid = resid;
5874 uiop->uio_iov->iov_base = iovbase;
5875 uiop->uio_iov->iov_len = iovlen;
5880 nfscl_lockderef(lckp);
5881 NFSFREECRED(newcred);
5882 nfscl_rellayout(layp, 0);
5888 * Make a copy of the mbuf chain and add an mbuf for null padding, as required.
5890 static struct mbuf *
5891 nfsm_copym(struct mbuf *m, int off, int xfer)
5893 struct mbuf *m2, *m3, *m4;
5897 m2 = m_copym(m, off, xfer, M_WAITOK);
5898 rem = NFSM_RNDUP(xfer) - xfer;
5901 * The zero padding to a multiple of 4 bytes is required by
5902 * the XDR. So that the mbufs copied by reference aren't
5903 * modified, add an mbuf with the zero'd bytes to the list.
5904 * rem will be a maximum of 3, so one zero'd uint32_t is
5908 while (m3->m_next != NULL)
5911 tl = NFSMTOD(m4, uint32_t *);
5913 mbuf_setlen(m4, rem);
5914 mbuf_setnext(m3, m4);
5920 * Find a file layout that will handle the first bytes of the requested
5921 * range and return the information from it needed to the I/O operation.
5924 nfscl_findlayoutforio(struct nfscllayout *lyp, uint64_t off, uint32_t rwaccess,
5925 struct nfsclflayout **retflpp)
5927 struct nfsclflayout *flp, *nflp, *rflp;
5932 /* For reading, do the Read list first and then the Write list. */
5934 if (rw == NFSV4OPEN_ACCESSREAD)
5935 flp = LIST_FIRST(&lyp->nfsly_flayread);
5937 flp = LIST_FIRST(&lyp->nfsly_flayrw);
5938 while (flp != NULL) {
5939 nflp = LIST_NEXT(flp, nfsfl_list);
5940 if (flp->nfsfl_off > off)
5942 if (flp->nfsfl_end > off &&
5943 (rflp == NULL || rflp->nfsfl_end < flp->nfsfl_end))
5947 if (rw == NFSV4OPEN_ACCESSREAD)
5948 rw = NFSV4OPEN_ACCESSWRITE;
5953 /* This one covers the most bytes starting at off. */
5961 * Do I/O using an NFSv4.1 or NFSv4.2 file layout.
5964 nfscl_doflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
5965 int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp,
5966 struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off,
5967 uint64_t len, int docommit, struct ucred *cred, NFSPROC_T *p)
5969 uint64_t io_off, rel_off, stripe_unit_size, transfer, xfer;
5970 int commit_thru_mds, error, stripe_index, stripe_pos, minorvers;
5973 struct nfsclds **dspp;
5976 rel_off = off - flp->nfsfl_patoff;
5977 stripe_unit_size = (flp->nfsfl_util >> 6) & 0x3ffffff;
5978 stripe_pos = (rel_off / stripe_unit_size + flp->nfsfl_stripe1) %
5979 dp->nfsdi_stripecnt;
5980 transfer = stripe_unit_size - (rel_off % stripe_unit_size);
5983 /* Loop around, doing I/O for each stripe unit. */
5984 while (len > 0 && error == 0) {
5985 stripe_index = nfsfldi_stripeindex(dp, stripe_pos);
5986 dspp = nfsfldi_addr(dp, stripe_index);
5987 if (((*dspp)->nfsclds_flags & NFSCLDS_MINORV2) != 0)
5988 minorvers = NFSV42_MINORVERSION;
5990 minorvers = NFSV41_MINORVERSION;
5991 if (len > transfer && docommit == 0)
5995 if ((flp->nfsfl_util & NFSFLAYUTIL_DENSE) != 0) {
5997 if (stripe_pos >= flp->nfsfl_fhcnt)
5999 fhp = flp->nfsfl_fh[stripe_pos];
6000 io_off = (rel_off / (stripe_unit_size *
6001 dp->nfsdi_stripecnt)) * stripe_unit_size +
6002 rel_off % stripe_unit_size;
6004 /* Sparse layout. */
6005 if (flp->nfsfl_fhcnt > 1) {
6006 if (stripe_index >= flp->nfsfl_fhcnt)
6008 fhp = flp->nfsfl_fh[stripe_index];
6009 } else if (flp->nfsfl_fhcnt == 1)
6010 fhp = flp->nfsfl_fh[0];
6015 if ((flp->nfsfl_util & NFSFLAYUTIL_COMMIT_THRU_MDS) != 0) {
6016 commit_thru_mds = 1;
6020 commit_thru_mds = 0;
6022 np->n_flag |= NDSCOMMIT;
6025 if (docommit != 0) {
6027 error = nfsrpc_commitds(vp, io_off, xfer,
6028 *dspp, fhp, NFS_VER4, minorvers, cred, p);
6031 * Set both eof and uio_resid = 0 to end any
6035 uiop->uio_resid = 0;
6038 np->n_flag &= ~NDSCOMMIT;
6041 } else if (rwflag == NFSV4OPEN_ACCESSREAD)
6042 error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp,
6043 io_off, xfer, fhp, 0, NFS_VER4, minorvers, cred, p);
6045 error = nfsrpc_writeds(vp, uiop, iomode, must_commit,
6046 stateidp, *dspp, io_off, xfer, fhp, commit_thru_mds,
6047 0, NFS_VER4, minorvers, cred, p);
6050 lyp->nfsly_flags |= NFSLY_WRITTEN;
6055 transfer = stripe_unit_size;
6056 stripe_pos = (stripe_pos + 1) % dp->nfsdi_stripecnt;
6065 * Do I/O using an NFSv4.1 flex file layout.
6068 nfscl_dofflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
6069 int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp,
6070 struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off,
6071 uint64_t len, int mirror, int docommit, struct mbuf *mp,
6072 struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p)
6074 uint64_t transfer, xfer;
6078 struct nfsclds **dspp;
6079 struct ucred *tcred;
6085 NFSCL_DEBUG(4, "nfscl_dofflayoutio: off=%ju len=%ju\n", (uintmax_t)off,
6087 /* Loop around, doing I/O for each stripe unit. */
6088 while (len > 0 && error == 0) {
6089 dspp = nfsfldi_addr(dp, 0);
6090 fhp = flp->nfsfl_ffm[mirror].fh[dp->nfsdi_versindex];
6091 stateidp = &flp->nfsfl_ffm[mirror].st;
6092 NFSCL_DEBUG(4, "mirror=%d vind=%d fhlen=%d st.seqid=0x%x\n",
6093 mirror, dp->nfsdi_versindex, fhp->nfh_len, stateidp->seqid);
6094 if ((dp->nfsdi_flags & NFSDI_TIGHTCOUPLED) == 0) {
6095 tcred = NFSNEWCRED(cred);
6096 tcred->cr_uid = flp->nfsfl_ffm[mirror].user;
6097 tcred->cr_groups[0] = flp->nfsfl_ffm[mirror].group;
6098 tcred->cr_ngroups = 1;
6101 if (rwflag == NFSV4OPEN_ACCESSREAD)
6102 transfer = dp->nfsdi_rsize;
6104 transfer = dp->nfsdi_wsize;
6106 np->n_flag |= NDSCOMMIT;
6108 if (len > transfer && docommit == 0)
6112 if (docommit != 0) {
6115 * Do last mirrored DS commit with this thread.
6117 if (mirror < flp->nfsfl_mirrorcnt - 1)
6118 error = nfsio_commitds(vp, off, xfer,
6119 *dspp, fhp, dp->nfsdi_vers,
6120 dp->nfsdi_minorvers, drpc, tcred,
6123 error = nfsrpc_commitds(vp, off, xfer,
6124 *dspp, fhp, dp->nfsdi_vers,
6125 dp->nfsdi_minorvers, tcred, p);
6126 NFSCL_DEBUG(4, "commitds=%d\n", error);
6127 if (error != 0 && error != EACCES && error !=
6130 "DS layreterr for commit\n");
6131 nfscl_dserr(NFSV4OP_COMMIT, error, dp,
6135 NFSCL_DEBUG(4, "aft nfsio_commitds=%d\n", error);
6138 * Set both eof and uio_resid = 0 to end any
6142 uiop->uio_resid = 0;
6145 np->n_flag &= ~NDSCOMMIT;
6148 } else if (rwflag == NFSV4OPEN_ACCESSREAD) {
6149 error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp,
6150 off, xfer, fhp, 1, dp->nfsdi_vers,
6151 dp->nfsdi_minorvers, tcred, p);
6152 NFSCL_DEBUG(4, "readds=%d\n", error);
6153 if (error != 0 && error != EACCES && error != ESTALE) {
6154 NFSCL_DEBUG(4, "DS layreterr for read\n");
6155 nfscl_dserr(NFSV4OP_READ, error, dp, lyp,
6159 if (flp->nfsfl_mirrorcnt == 1) {
6160 error = nfsrpc_writeds(vp, uiop, iomode,
6161 must_commit, stateidp, *dspp, off, xfer,
6162 fhp, 0, 1, dp->nfsdi_vers,
6163 dp->nfsdi_minorvers, tcred, p);
6166 lyp->nfsly_flags |= NFSLY_WRITTEN;
6170 m = nfsm_copym(mp, rel_off, xfer);
6171 NFSCL_DEBUG(4, "mcopy reloff=%d xfer=%jd\n",
6172 rel_off, (uintmax_t)xfer);
6174 * Do last write to a mirrored DS with this
6177 if (mirror < flp->nfsfl_mirrorcnt - 1)
6178 error = nfsio_writedsmir(vp, iomode,
6179 must_commit, stateidp, *dspp, off,
6180 xfer, fhp, m, dp->nfsdi_vers,
6181 dp->nfsdi_minorvers, drpc, tcred,
6184 error = nfsrpc_writedsmir(vp, iomode,
6185 must_commit, stateidp, *dspp, off,
6186 xfer, fhp, m, dp->nfsdi_vers,
6187 dp->nfsdi_minorvers, tcred, p);
6188 NFSCL_DEBUG(4, "nfsio_writedsmir=%d\n", error);
6189 if (error != 0 && error != EACCES && error !=
6192 "DS layreterr for write\n");
6193 nfscl_dserr(NFSV4OP_WRITE, error, dp,
6198 NFSCL_DEBUG(4, "aft read/writeds=%d\n", error);
6204 if ((dp->nfsdi_flags & NFSDI_TIGHTCOUPLED) == 0)
6207 NFSCL_DEBUG(4, "eo nfscl_dofflayoutio=%d\n", error);
6212 * The actual read RPC done to a DS.
6215 nfsrpc_readds(vnode_t vp, struct uio *uiop, nfsv4stateid_t *stateidp, int *eofp,
6216 struct nfsclds *dsp, uint64_t io_off, int len, struct nfsfh *fhp, int flex,
6217 int vers, int minorvers, struct ucred *cred, NFSPROC_T *p)
6220 int attrflag, error, retlen;
6221 struct nfsrv_descript nfsd;
6222 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
6223 struct nfsrv_descript *nd = &nfsd;
6224 struct nfssockreq *nrp;
6228 if (vers == 0 || vers == NFS_VER4) {
6229 nfscl_reqstart(nd, NFSPROC_READDS, nmp, fhp->nfh_fh,
6230 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers);
6232 NFSCL_DEBUG(4, "nfsrpc_readds: vers4 minvers=%d\n", minorvers);
6234 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
6236 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO);
6238 nfscl_reqstart(nd, NFSPROC_READ, nmp, fhp->nfh_fh,
6239 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers);
6240 NFSCL_DEBUG(4, "nfsrpc_readds: vers3\n");
6242 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED * 3);
6243 txdr_hyper(io_off, tl);
6244 *(tl + 2) = txdr_unsigned(len);
6245 nrp = dsp->nfsclds_sockp;
6246 NFSCL_DEBUG(4, "nfsrpc_readds: nrp=%p\n", nrp);
6248 /* If NULL, use the MDS socket. */
6249 nrp = &nmp->nm_sockreq;
6250 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
6251 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess);
6252 NFSCL_DEBUG(4, "nfsrpc_readds: stat=%d err=%d\n", nd->nd_repstat,
6256 if (vers == NFS_VER3) {
6257 error = nfscl_postop_attr(nd, &na, &attrflag, NULL);
6258 NFSCL_DEBUG(4, "nfsrpc_readds: postop=%d\n", error);
6262 if (nd->nd_repstat != 0) {
6263 error = nd->nd_repstat;
6266 if (vers == NFS_VER3) {
6267 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
6268 *eofp = fxdr_unsigned(int, *(tl + 1));
6270 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
6271 *eofp = fxdr_unsigned(int, *tl);
6273 NFSM_STRSIZ(retlen, len);
6274 NFSCL_DEBUG(4, "nfsrpc_readds: retlen=%d eof=%d\n", retlen, *eofp);
6275 error = nfsm_mbufuio(nd, uiop, retlen);
6277 if (nd->nd_mrep != NULL)
6278 mbuf_freem(nd->nd_mrep);
6283 * The actual write RPC done to a DS.
6286 nfsrpc_writeds(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
6287 nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len,
6288 struct nfsfh *fhp, int commit_thru_mds, int flex, int vers, int minorvers,
6289 struct ucred *cred, NFSPROC_T *p)
6292 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
6293 int attrflag, error, rlen, commit, committed = NFSWRITE_FILESYNC;
6295 struct nfsrv_descript nfsd;
6296 struct nfsrv_descript *nd = &nfsd;
6297 struct nfssockreq *nrp;
6300 KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1"));
6302 if (vers == 0 || vers == NFS_VER4) {
6303 nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh,
6304 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers);
6305 NFSCL_DEBUG(4, "nfsrpc_writeds: vers4 minvers=%d\n", minorvers);
6308 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
6310 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO);
6311 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
6313 nfscl_reqstart(nd, NFSPROC_WRITE, nmp, fhp->nfh_fh,
6314 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers);
6315 NFSCL_DEBUG(4, "nfsrpc_writeds: vers3\n");
6316 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED);
6318 txdr_hyper(io_off, tl);
6320 if (vers == NFS_VER3)
6321 *tl++ = txdr_unsigned(len);
6322 *tl++ = txdr_unsigned(*iomode);
6323 *tl = txdr_unsigned(len);
6324 nfsm_uiombuf(nd, uiop, len);
6325 nrp = dsp->nfsclds_sockp;
6327 /* If NULL, use the MDS socket. */
6328 nrp = &nmp->nm_sockreq;
6329 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
6330 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess);
6331 NFSCL_DEBUG(4, "nfsrpc_writeds: err=%d stat=%d\n", error,
6335 if (nd->nd_repstat != 0) {
6337 * In case the rpc gets retried, roll
6338 * the uio fileds changed by nfsm_uiombuf()
6341 uiop->uio_offset -= len;
6342 uio_uio_resid_add(uiop, len);
6343 uio_iov_base_add(uiop, -len);
6344 uio_iov_len_add(uiop, len);
6345 error = nd->nd_repstat;
6347 if (vers == NFS_VER3) {
6348 error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL,
6350 NFSCL_DEBUG(4, "nfsrpc_writeds: wcc_data=%d\n", error);
6354 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF);
6355 rlen = fxdr_unsigned(int, *tl++);
6356 NFSCL_DEBUG(4, "nfsrpc_writeds: len=%d rlen=%d\n", len, rlen);
6360 } else if (rlen < len) {
6361 backup = len - rlen;
6362 uio_iov_base_add(uiop, -(backup));
6363 uio_iov_len_add(uiop, backup);
6364 uiop->uio_offset -= backup;
6365 uio_uio_resid_add(uiop, backup);
6368 commit = fxdr_unsigned(int, *tl++);
6371 * Return the lowest commitment level
6372 * obtained by any of the RPCs.
6374 if (committed == NFSWRITE_FILESYNC)
6376 else if (committed == NFSWRITE_DATASYNC &&
6377 commit == NFSWRITE_UNSTABLE)
6379 if (commit_thru_mds != 0) {
6381 if (!NFSHASWRITEVERF(nmp)) {
6382 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
6383 NFSSETWRITEVERF(nmp);
6384 } else if (NFSBCMP(tl, nmp->nm_verf, NFSX_VERF)) {
6386 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
6391 if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) {
6392 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
6393 dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF;
6394 } else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) {
6396 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
6402 if (nd->nd_mrep != NULL)
6403 mbuf_freem(nd->nd_mrep);
6404 *iomode = committed;
6405 if (nd->nd_repstat != 0 && error == 0)
6406 error = nd->nd_repstat;
6411 * The actual write RPC done to a DS.
6412 * This variant is called from a separate kernel process for mirrors.
6413 * Any short write is considered an IO error.
6416 nfsrpc_writedsmir(vnode_t vp, int *iomode, int *must_commit,
6417 nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len,
6418 struct nfsfh *fhp, struct mbuf *m, int vers, int minorvers,
6419 struct ucred *cred, NFSPROC_T *p)
6422 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
6423 int attrflag, error, commit, committed = NFSWRITE_FILESYNC, rlen;
6424 struct nfsrv_descript nfsd;
6425 struct nfsrv_descript *nd = &nfsd;
6426 struct nfssockreq *nrp;
6430 if (vers == 0 || vers == NFS_VER4) {
6431 nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh,
6432 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers);
6434 NFSCL_DEBUG(4, "nfsrpc_writedsmir: vers4 minvers=%d\n",
6436 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
6437 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
6439 nfscl_reqstart(nd, NFSPROC_WRITE, nmp, fhp->nfh_fh,
6440 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers);
6441 NFSCL_DEBUG(4, "nfsrpc_writedsmir: vers3\n");
6442 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED);
6444 txdr_hyper(io_off, tl);
6446 if (vers == NFS_VER3)
6447 *tl++ = txdr_unsigned(len);
6448 *tl++ = txdr_unsigned(*iomode);
6449 *tl = txdr_unsigned(len);
6451 /* Put data in mbuf chain. */
6452 nd->nd_mb->m_next = m;
6453 /* Set nd_mb and nd_bpos to end of data. */
6454 while (m->m_next != NULL)
6457 nd->nd_bpos = mtod(m, char *) + m->m_len;
6458 NFSCL_DEBUG(4, "nfsrpc_writedsmir: lastmb len=%d\n", m->m_len);
6460 nrp = dsp->nfsclds_sockp;
6462 /* If NULL, use the MDS socket. */
6463 nrp = &nmp->nm_sockreq;
6464 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
6465 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess);
6466 NFSCL_DEBUG(4, "nfsrpc_writedsmir: err=%d stat=%d\n", error,
6470 if (nd->nd_repstat != 0)
6471 error = nd->nd_repstat;
6473 if (vers == NFS_VER3) {
6474 error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL,
6476 NFSCL_DEBUG(4, "nfsrpc_writedsmir: wcc_data=%d\n",
6481 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF);
6482 rlen = fxdr_unsigned(int, *tl++);
6483 NFSCL_DEBUG(4, "nfsrpc_writedsmir: len=%d rlen=%d\n", len,
6487 NFSCL_DEBUG(4, "nfsrpc_writedsmir: len=%d rlen=%d\n",
6491 commit = fxdr_unsigned(int, *tl++);
6494 * Return the lowest commitment level
6495 * obtained by any of the RPCs.
6497 if (committed == NFSWRITE_FILESYNC)
6499 else if (committed == NFSWRITE_DATASYNC &&
6500 commit == NFSWRITE_UNSTABLE)
6503 if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) {
6504 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
6505 dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF;
6506 } else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) {
6508 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
6513 if (nd->nd_mrep != NULL)
6514 mbuf_freem(nd->nd_mrep);
6515 *iomode = committed;
6516 if (nd->nd_repstat != 0 && error == 0)
6517 error = nd->nd_repstat;
6522 * Start up the thread that will execute nfsrpc_writedsmir().
6525 start_writedsmir(void *arg, int pending)
6527 struct nfsclwritedsdorpc *drpc;
6529 drpc = (struct nfsclwritedsdorpc *)arg;
6530 drpc->err = nfsrpc_writedsmir(drpc->vp, &drpc->iomode,
6531 &drpc->must_commit, drpc->stateidp, drpc->dsp, drpc->off, drpc->len,
6532 drpc->fhp, drpc->m, drpc->vers, drpc->minorvers, drpc->cred,
6535 NFSCL_DEBUG(4, "start_writedsmir: err=%d\n", drpc->err);
6539 * Set up the write DS mirror call for the pNFS I/O thread.
6542 nfsio_writedsmir(vnode_t vp, int *iomode, int *must_commit,
6543 nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t off, int len,
6544 struct nfsfh *fhp, struct mbuf *m, int vers, int minorvers,
6545 struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p)
6552 drpc->iomode = *iomode;
6553 drpc->must_commit = *must_commit;
6554 drpc->stateidp = stateidp;
6561 drpc->minorvers = minorvers;
6566 if (nfs_pnfsiothreads != 0) {
6567 ret = nfs_pnfsio(start_writedsmir, drpc);
6568 NFSCL_DEBUG(4, "nfsio_writedsmir: nfs_pnfsio=%d\n", ret);
6571 error = nfsrpc_writedsmir(vp, iomode, must_commit, stateidp,
6572 dsp, off, len, fhp, m, vers, minorvers, cred, p);
6573 NFSCL_DEBUG(4, "nfsio_writedsmir: error=%d\n", error);
6578 * Free up the nfsclds structure.
6581 nfscl_freenfsclds(struct nfsclds *dsp)
6587 if (dsp->nfsclds_sockp != NULL) {
6588 NFSFREECRED(dsp->nfsclds_sockp->nr_cred);
6589 NFSFREEMUTEX(&dsp->nfsclds_sockp->nr_mtx);
6590 free(dsp->nfsclds_sockp->nr_nam, M_SONAME);
6591 free(dsp->nfsclds_sockp, M_NFSSOCKREQ);
6593 NFSFREEMUTEX(&dsp->nfsclds_mtx);
6594 NFSFREEMUTEX(&dsp->nfsclds_sess.nfsess_mtx);
6595 for (i = 0; i < NFSV4_CBSLOTS; i++) {
6596 if (dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply != NULL)
6598 dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply);
6600 free(dsp, M_NFSCLDS);
6603 static enum nfsclds_state
6604 nfscl_getsameserver(struct nfsmount *nmp, struct nfsclds *newdsp,
6605 struct nfsclds **retdspp, uint32_t *sequencep)
6607 struct nfsclds *dsp;
6611 * Search the list of nfsclds structures for one with the same
6615 TAILQ_FOREACH(dsp, &nmp->nm_sess, nfsclds_list) {
6616 if (dsp->nfsclds_servownlen == newdsp->nfsclds_servownlen &&
6617 dsp->nfsclds_servownlen != 0 &&
6618 !NFSBCMP(dsp->nfsclds_serverown, newdsp->nfsclds_serverown,
6619 dsp->nfsclds_servownlen) &&
6620 dsp->nfsclds_sess.nfsess_defunct == 0) {
6621 NFSCL_DEBUG(4, "fnd same fdsp=%p dsp=%p flg=0x%x\n",
6622 TAILQ_FIRST(&nmp->nm_sess), dsp,
6623 dsp->nfsclds_flags);
6625 /* Get sequenceid# from first entry. */
6627 dsp->nfsclds_sess.nfsess_sequenceid;
6630 /* Server major id matches. */
6631 if ((dsp->nfsclds_flags & NFSCLDS_DS) != 0) {
6633 return (NFSDSP_USETHISSESSION);
6639 return (NFSDSP_SEQTHISSESSION);
6640 return (NFSDSP_NOTFOUND);
6644 * NFS commit rpc to a NFSv4.1 DS.
6647 nfsrpc_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp,
6648 struct nfsfh *fhp, int vers, int minorvers, struct ucred *cred,
6652 struct nfsrv_descript nfsd, *nd = &nfsd;
6653 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
6654 struct nfssockreq *nrp;
6656 int attrflag, error;
6659 if (vers == 0 || vers == NFS_VER4) {
6660 nfscl_reqstart(nd, NFSPROC_COMMITDS, nmp, fhp->nfh_fh,
6661 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers);
6664 nfscl_reqstart(nd, NFSPROC_COMMIT, nmp, fhp->nfh_fh,
6665 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers);
6666 NFSCL_DEBUG(4, "nfsrpc_commitds: vers=%d minvers=%d\n", vers,
6668 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
6669 txdr_hyper(offset, tl);
6671 *tl = txdr_unsigned(cnt);
6672 nrp = dsp->nfsclds_sockp;
6674 /* If NULL, use the MDS socket. */
6675 nrp = &nmp->nm_sockreq;
6676 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
6677 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess);
6678 NFSCL_DEBUG(4, "nfsrpc_commitds: err=%d stat=%d\n", error,
6682 if (nd->nd_repstat == 0) {
6683 if (vers == NFS_VER3) {
6684 error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL,
6686 NFSCL_DEBUG(4, "nfsrpc_commitds: wccdata=%d\n", error);
6690 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
6692 if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) {
6693 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
6694 error = NFSERR_STALEWRITEVERF;
6699 if (error == 0 && nd->nd_repstat != 0)
6700 error = nd->nd_repstat;
6701 mbuf_freem(nd->nd_mrep);
6706 * Start up the thread that will execute nfsrpc_commitds().
6709 start_commitds(void *arg, int pending)
6711 struct nfsclwritedsdorpc *drpc;
6713 drpc = (struct nfsclwritedsdorpc *)arg;
6714 drpc->err = nfsrpc_commitds(drpc->vp, drpc->off, drpc->len,
6715 drpc->dsp, drpc->fhp, drpc->vers, drpc->minorvers, drpc->cred,
6718 NFSCL_DEBUG(4, "start_commitds: err=%d\n", drpc->err);
6722 * Set up the commit DS mirror call for the pNFS I/O thread.
6725 nfsio_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp,
6726 struct nfsfh *fhp, int vers, int minorvers,
6727 struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p)
6739 drpc->minorvers = minorvers;
6744 if (nfs_pnfsiothreads != 0) {
6745 ret = nfs_pnfsio(start_commitds, drpc);
6746 NFSCL_DEBUG(4, "nfsio_commitds: nfs_pnfsio=%d\n", ret);
6749 error = nfsrpc_commitds(vp, offset, cnt, dsp, fhp, vers,
6750 minorvers, cred, p);
6751 NFSCL_DEBUG(4, "nfsio_commitds: error=%d\n", error);
6759 nfsrpc_advise(vnode_t vp, off_t offset, uint64_t cnt, int advise,
6760 struct ucred *cred, NFSPROC_T *p)
6763 struct nfsrv_descript nfsd, *nd = &nfsd;
6767 NFSZERO_ATTRBIT(&hints);
6768 if (advise == POSIX_FADV_WILLNEED)
6769 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED);
6770 else if (advise == POSIX_FADV_DONTNEED)
6771 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED);
6774 NFSCL_REQSTART(nd, NFSPROC_IOADVISE, vp);
6775 nfsm_stateidtom(nd, NULL, NFSSTATEID_PUTALLZERO);
6776 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER);
6777 txdr_hyper(offset, tl);
6779 txdr_hyper(cnt, tl);
6780 nfsrv_putattrbit(nd, &hints);
6781 error = nfscl_request(nd, vp, p, cred, NULL);
6784 if (nd->nd_repstat != 0)
6785 error = nd->nd_repstat;
6786 mbuf_freem(nd->nd_mrep);
6792 * NFS advise rpc to a NFSv4.2 DS.
6795 nfsrpc_adviseds(vnode_t vp, uint64_t offset, int cnt, int advise,
6796 struct nfsclds *dsp, struct nfsfh *fhp, int vers, int minorvers,
6797 struct ucred *cred, NFSPROC_T *p)
6800 struct nfsrv_descript nfsd, *nd = &nfsd;
6801 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
6802 struct nfssockreq *nrp;
6806 /* For NFS DSs prior to NFSv4.2, just return OK. */
6807 if (vers == NFS_VER3 || minorversion < NFSV42_MINORVERSION)
6809 NFSZERO_ATTRBIT(&hints);
6810 if (advise == POSIX_FADV_WILLNEED)
6811 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED);
6812 else if (advise == POSIX_FADV_DONTNEED)
6813 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED);
6817 nfscl_reqstart(nd, NFSPROC_IOADVISEDS, nmp, fhp->nfh_fh,
6818 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers);
6820 NFSCL_DEBUG(4, "nfsrpc_adviseds: vers=%d minvers=%d\n", vers,
6822 nfsm_stateidtom(nd, NULL, NFSSTATEID_PUTALLZERO);
6823 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
6824 txdr_hyper(offset, tl);
6826 *tl = txdr_unsigned(cnt);
6827 nfsrv_putattrbit(nd, &hints);
6828 nrp = dsp->nfsclds_sockp;
6830 /* If NULL, use the MDS socket. */
6831 nrp = &nmp->nm_sockreq;
6832 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
6833 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess);
6834 NFSCL_DEBUG(4, "nfsrpc_adviseds: err=%d stat=%d\n", error,
6838 if (nd->nd_repstat != 0)
6839 error = nd->nd_repstat;
6840 mbuf_freem(nd->nd_mrep);
6845 * Start up the thread that will execute nfsrpc_commitds().
6848 start_adviseds(void *arg, int pending)
6850 struct nfsclwritedsdorpc *drpc;
6852 drpc = (struct nfsclwritedsdorpc *)arg;
6853 drpc->err = nfsrpc_adviseds(drpc->vp, drpc->off, drpc->len,
6854 drpc->advise, drpc->dsp, drpc->fhp, drpc->vers, drpc->minorvers,
6855 drpc->cred, drpc->p);
6857 NFSCL_DEBUG(4, "start_adviseds: err=%d\n", drpc->err);
6861 * Set up the commit DS mirror call for the pNFS I/O thread.
6864 nfsio_adviseds(vnode_t vp, uint64_t offset, int cnt, int advise,
6865 struct nfsclds *dsp, struct nfsfh *fhp, int vers, int minorvers,
6866 struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p)
6875 drpc->advise = advise;
6879 drpc->minorvers = minorvers;
6884 if (nfs_pnfsiothreads != 0) {
6885 ret = nfs_pnfsio(start_adviseds, drpc);
6886 NFSCL_DEBUG(4, "nfsio_adviseds: nfs_pnfsio=%d\n", ret);
6889 error = nfsrpc_adviseds(vp, offset, cnt, advise, dsp, fhp, vers,
6890 minorvers, cred, p);
6891 NFSCL_DEBUG(4, "nfsio_adviseds: error=%d\n", error);
6897 * Do the Allocate operation, retrying for recovery.
6900 nfsrpc_allocate(vnode_t vp, off_t off, off_t len, struct nfsvattr *nap,
6901 int *attrflagp, struct ucred *cred, NFSPROC_T *p, void *stuff)
6903 int error, expireret = 0, retrycnt, nostateid;
6904 uint32_t clidrev = 0;
6905 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
6906 struct nfsfh *nfhp = NULL;
6907 nfsv4stateid_t stateid;
6915 tmp_off = off + len;
6917 if (tmp_off > nmp->nm_maxfilesize || tmp_off < off) {
6921 if (nmp->nm_clp != NULL)
6922 clidrev = nmp->nm_clp->nfsc_clientidrev;
6924 nfhp = VTONFS(vp)->n_fhp;
6929 nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
6930 NFSV4OPEN_ACCESSWRITE, 0, cred, p, &stateid, &lckp);
6931 if (stateid.other[0] == 0 && stateid.other[1] == 0 &&
6932 stateid.other[2] == 0) {
6934 NFSCL_DEBUG(1, "stateid0 in allocate\n");
6938 * Not finding a stateid should probably never happen,
6939 * but just return an error for this case.
6944 error = nfsrpc_allocaterpc(vp, off, len, &stateid,
6945 nap, attrflagp, cred, p, stuff);
6946 if (error == NFSERR_STALESTATEID)
6947 nfscl_initiate_recovery(nmp->nm_clp);
6949 nfscl_lockderef(lckp);
6950 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
6951 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
6952 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
6953 (void) nfs_catnap(PZERO, error, "nfs_allocate");
6954 } else if ((error == NFSERR_EXPIRED ||
6955 error == NFSERR_BADSTATEID) && clidrev != 0) {
6956 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
6959 } while (error == NFSERR_GRACE || error == NFSERR_DELAY ||
6960 error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION ||
6961 error == NFSERR_STALEDONTRECOVER ||
6962 (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
6963 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
6964 expireret == 0 && clidrev != 0 && retrycnt < 4));
6965 if (error != 0 && retrycnt >= 4)
6974 nfsrpc_allocaterpc(vnode_t vp, off_t off, off_t len, nfsv4stateid_t *stateidp,
6975 struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p,
6980 struct nfsrv_descript nfsd;
6981 struct nfsrv_descript *nd = &nfsd;
6982 nfsattrbit_t attrbits;
6985 NFSCL_REQSTART(nd, NFSPROC_ALLOCATE, vp);
6986 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
6987 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED);
6988 txdr_hyper(off, tl); tl += 2;
6989 txdr_hyper(len, tl); tl += 2;
6990 *tl = txdr_unsigned(NFSV4OP_GETATTR);
6991 NFSGETATTR_ATTRBIT(&attrbits);
6992 nfsrv_putattrbit(nd, &attrbits);
6993 error = nfscl_request(nd, vp, p, cred, stuff);
6996 if (nd->nd_repstat == 0) {
6997 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
6998 error = nfsm_loadattr(nd, nap);
7000 *attrflagp = NFS_LATTR_NOSHRINK;
7002 error = nd->nd_repstat;
7004 mbuf_freem(nd->nd_mrep);
7009 * Set up the XDR arguments for the LayoutGet operation.
7012 nfsrv_setuplayoutget(struct nfsrv_descript *nd, int iomode, uint64_t offset,
7013 uint64_t len, uint64_t minlen, nfsv4stateid_t *stateidp, int layouttype,
7014 int layoutlen, int usecurstateid)
7018 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
7020 *tl++ = newnfs_false; /* Don't signal availability. */
7021 *tl++ = txdr_unsigned(layouttype);
7022 *tl++ = txdr_unsigned(iomode);
7023 txdr_hyper(offset, tl);
7025 txdr_hyper(len, tl);
7027 txdr_hyper(minlen, tl);
7029 if (usecurstateid != 0) {
7030 /* Special stateid for Current stateid. */
7031 *tl++ = txdr_unsigned(1);
7036 *tl++ = txdr_unsigned(stateidp->seqid);
7037 NFSCL_DEBUG(4, "layget seq=%d\n", (int)stateidp->seqid);
7038 *tl++ = stateidp->other[0];
7039 *tl++ = stateidp->other[1];
7040 *tl++ = stateidp->other[2];
7042 *tl = txdr_unsigned(layoutlen);
7046 * Parse the reply for a successful LayoutGet operation.
7049 nfsrv_parselayoutget(struct nfsmount *nmp, struct nfsrv_descript *nd,
7050 nfsv4stateid_t *stateidp, int *retonclosep, struct nfsclflayouthead *flhp)
7053 struct nfsclflayout *flp, *prevflp, *tflp;
7054 int cnt, error, fhcnt, gotiomode, i, iomode, j, k, l, laytype, nfhlen;
7056 uint64_t retlen, off;
7062 NFSCL_DEBUG(4, "in nfsrv_parselayoutget\n");
7066 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_STATEID);
7071 stateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
7072 NFSCL_DEBUG(4, "retoncls=%d stseq=%d\n", *retonclosep,
7073 (int)stateidp->seqid);
7074 stateidp->other[0] = *tl++;
7075 stateidp->other[1] = *tl++;
7076 stateidp->other[2] = *tl++;
7077 cnt = fxdr_unsigned(int, *tl);
7078 NFSCL_DEBUG(4, "layg cnt=%d\n", cnt);
7079 if (cnt <= 0 || cnt > 10000) {
7080 /* Don't accept more than 10000 layouts in reply. */
7081 error = NFSERR_BADXDR;
7084 for (i = 0; i < cnt; i++) {
7085 /* Dissect to the layout type. */
7086 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER +
7088 off = fxdr_hyper(tl); tl += 2;
7089 retlen = fxdr_hyper(tl); tl += 2;
7090 iomode = fxdr_unsigned(int, *tl++);
7091 laytype = fxdr_unsigned(int, *tl);
7092 NFSCL_DEBUG(4, "layt=%d off=%ju len=%ju iom=%d\n", laytype,
7093 (uintmax_t)off, (uintmax_t)retlen, iomode);
7094 /* Ignore length of layout body for now. */
7095 if (laytype == NFSLAYOUT_NFSV4_1_FILES) {
7096 /* Parse the File layout up to fhcnt. */
7097 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED +
7098 NFSX_HYPER + NFSX_V4DEVICEID);
7099 fhcnt = fxdr_unsigned(int, *(tl + 4 +
7100 NFSX_V4DEVICEID / NFSX_UNSIGNED));
7101 NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt);
7102 if (fhcnt < 0 || fhcnt > 100) {
7103 /* Don't accept more than 100 file handles. */
7104 error = NFSERR_BADXDR;
7108 flp = malloc(sizeof(*flp) + fhcnt *
7109 sizeof(struct nfsfh *), M_NFSFLAYOUT,
7112 flp = malloc(sizeof(*flp), M_NFSFLAYOUT,
7114 flp->nfsfl_flags = NFSFL_FILE;
7115 flp->nfsfl_fhcnt = 0;
7116 flp->nfsfl_devp = NULL;
7117 flp->nfsfl_off = off;
7118 if (flp->nfsfl_off + retlen < flp->nfsfl_off)
7119 flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off;
7121 flp->nfsfl_end = flp->nfsfl_off + retlen;
7122 flp->nfsfl_iomode = iomode;
7123 if (gotiomode == -1)
7124 gotiomode = flp->nfsfl_iomode;
7125 /* Ignore layout body length for now. */
7126 NFSBCOPY(tl, flp->nfsfl_dev, NFSX_V4DEVICEID);
7127 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
7128 flp->nfsfl_util = fxdr_unsigned(uint32_t, *tl++);
7129 NFSCL_DEBUG(4, "flutil=0x%x\n", flp->nfsfl_util);
7130 mtx_lock(&nmp->nm_mtx);
7131 if (nmp->nm_minorvers > 1 && (flp->nfsfl_util &
7132 NFSFLAYUTIL_IOADVISE_THRU_MDS) != 0)
7133 nmp->nm_privflag |= NFSMNTP_IOADVISETHRUMDS;
7134 mtx_unlock(&nmp->nm_mtx);
7135 flp->nfsfl_stripe1 = fxdr_unsigned(uint32_t, *tl++);
7136 flp->nfsfl_patoff = fxdr_hyper(tl); tl += 2;
7137 NFSCL_DEBUG(4, "stripe1=%u poff=%ju\n",
7138 flp->nfsfl_stripe1, (uintmax_t)flp->nfsfl_patoff);
7139 for (j = 0; j < fhcnt; j++) {
7140 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
7141 nfhlen = fxdr_unsigned(int, *tl);
7142 if (nfhlen <= 0 || nfhlen > NFSX_V4FHMAX) {
7143 error = NFSERR_BADXDR;
7146 nfhp = malloc(sizeof(*nfhp) + nfhlen - 1,
7148 flp->nfsfl_fh[j] = nfhp;
7150 nfhp->nfh_len = nfhlen;
7151 NFSM_DISSECT(cp, uint8_t *, NFSM_RNDUP(nfhlen));
7152 NFSBCOPY(cp, nfhp->nfh_fh, nfhlen);
7154 } else if (laytype == NFSLAYOUT_FLEXFILE) {
7155 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED +
7157 mirrorcnt = fxdr_unsigned(int, *(tl + 2));
7158 NFSCL_DEBUG(4, "mirrorcnt=%d\n", mirrorcnt);
7159 if (mirrorcnt < 1 || mirrorcnt > NFSDEV_MAXMIRRORS) {
7160 error = NFSERR_BADXDR;
7163 flp = malloc(sizeof(*flp) + mirrorcnt *
7164 sizeof(struct nfsffm), M_NFSFLAYOUT, M_WAITOK);
7165 flp->nfsfl_flags = NFSFL_FLEXFILE;
7166 flp->nfsfl_mirrorcnt = mirrorcnt;
7167 for (j = 0; j < mirrorcnt; j++)
7168 flp->nfsfl_ffm[j].devp = NULL;
7169 flp->nfsfl_off = off;
7170 if (flp->nfsfl_off + retlen < flp->nfsfl_off)
7171 flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off;
7173 flp->nfsfl_end = flp->nfsfl_off + retlen;
7174 flp->nfsfl_iomode = iomode;
7175 if (gotiomode == -1)
7176 gotiomode = flp->nfsfl_iomode;
7177 flp->nfsfl_stripeunit = fxdr_hyper(tl);
7178 NFSCL_DEBUG(4, "stripeunit=%ju\n",
7179 (uintmax_t)flp->nfsfl_stripeunit);
7180 for (j = 0; j < mirrorcnt; j++) {
7181 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
7182 k = fxdr_unsigned(int, *tl);
7183 if (k < 1 || k > 128) {
7184 error = NFSERR_BADXDR;
7187 NFSCL_DEBUG(4, "servercnt=%d\n", k);
7188 for (l = 0; l < k; l++) {
7189 NFSM_DISSECT(tl, uint32_t *,
7190 NFSX_V4DEVICEID + NFSX_STATEID +
7193 /* Just use the first server. */
7195 flp->nfsfl_ffm[j].dev,
7197 tl += (NFSX_V4DEVICEID /
7200 flp->nfsfl_ffm[j].st.seqid =
7202 flp->nfsfl_ffm[j].st.other[0] =
7204 flp->nfsfl_ffm[j].st.other[1] =
7206 flp->nfsfl_ffm[j].st.other[2] =
7208 NFSCL_DEBUG(4, "st.seqid=%u "
7209 "st.o0=0x%x st.o1=0x%x "
7211 flp->nfsfl_ffm[j].st.seqid,
7212 flp->nfsfl_ffm[j].st.other[0],
7213 flp->nfsfl_ffm[j].st.other[1],
7214 flp->nfsfl_ffm[j].st.other[2]);
7216 tl += ((NFSX_V4DEVICEID +
7220 fhcnt = fxdr_unsigned(int, *tl);
7221 NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt);
7223 fhcnt > NFSDEV_MAXVERS) {
7224 error = NFSERR_BADXDR;
7227 for (m = 0; m < fhcnt; m++) {
7228 NFSM_DISSECT(tl, uint32_t *,
7230 nfhlen = fxdr_unsigned(int,
7232 NFSCL_DEBUG(4, "nfhlen=%d\n",
7234 if (nfhlen <= 0 || nfhlen >
7236 error = NFSERR_BADXDR;
7239 NFSM_DISSECT(cp, uint8_t *,
7240 NFSM_RNDUP(nfhlen));
7242 flp->nfsfl_ffm[j].fhcnt
7246 nfhlen - 1, M_NFSFH,
7248 flp->nfsfl_ffm[j].fh[m]
7250 nfhp->nfh_len = nfhlen;
7258 /* Now, get the ffsd_user/ffds_group. */
7259 error = nfsrv_parseug(nd, 0, &user,
7261 NFSCL_DEBUG(4, "after parseu=%d\n",
7264 error = nfsrv_parseug(nd, 1,
7265 &user, &grp, curthread);
7266 NFSCL_DEBUG(4, "aft parseg=%d\n",
7270 NFSCL_DEBUG(4, "user=%d group=%d\n",
7273 flp->nfsfl_ffm[j].user = user;
7274 flp->nfsfl_ffm[j].group = grp;
7276 "usr=%d grp=%d\n", user,
7281 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
7282 flp->nfsfl_fflags = fxdr_unsigned(uint32_t, *tl++);
7285 * At this time, there is no flag.
7286 * NFSFLEXFLAG_IOADVISE_THRU_MDS might need to be
7287 * added, or it may never exist?
7289 mtx_lock(&nmp->nm_mtx);
7290 if (nmp->nm_minorvers > 1 && (flp->nfsfl_fflags &
7291 NFSFLEXFLAG_IOADVISE_THRU_MDS) != 0)
7292 nmp->nm_privflag |= NFSMNTP_IOADVISETHRUMDS;
7293 mtx_unlock(&nmp->nm_mtx);
7295 flp->nfsfl_statshint = fxdr_unsigned(uint32_t, *tl);
7296 NFSCL_DEBUG(4, "fflags=0x%x statshint=%d\n",
7297 flp->nfsfl_fflags, flp->nfsfl_statshint);
7299 error = NFSERR_BADXDR;
7302 if (flp->nfsfl_iomode == gotiomode) {
7303 /* Keep the list in increasing offset order. */
7304 tflp = LIST_FIRST(flhp);
7306 while (tflp != NULL &&
7307 tflp->nfsfl_off < flp->nfsfl_off) {
7309 tflp = LIST_NEXT(tflp, nfsfl_list);
7311 if (prevflp == NULL)
7312 LIST_INSERT_HEAD(flhp, flp, nfsfl_list);
7314 LIST_INSERT_AFTER(prevflp, flp,
7316 NFSCL_DEBUG(4, "flp inserted\n");
7318 printf("nfscl_layoutget(): got wrong iomode\n");
7319 nfscl_freeflayout(flp);
7324 NFSCL_DEBUG(4, "eo nfsrv_parselayoutget=%d\n", error);
7325 if (error != 0 && flp != NULL)
7326 nfscl_freeflayout(flp);
7331 * Parse a user/group digit string.
7334 nfsrv_parseug(struct nfsrv_descript *nd, int dogrp, uid_t *uidp, gid_t *gidp,
7338 char *cp, *str, str0[NFSV4_SMALLSTR + 1];
7342 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
7343 len = fxdr_unsigned(uint32_t, *tl);
7345 if (len > NFSV4_OPAQUELIMIT) {
7346 error = NFSERR_BADXDR;
7349 NFSCL_DEBUG(4, "nfsrv_parseug: len=%d\n", len);
7352 *gidp = GID_NOGROUP;
7357 if (len > NFSV4_SMALLSTR)
7358 str = malloc(len + 1, M_TEMP, M_WAITOK);
7361 NFSM_DISSECT(cp, char *, NFSM_RNDUP(len));
7362 NFSBCOPY(cp, str, len);
7364 NFSCL_DEBUG(4, "nfsrv_parseug: str=%s\n", str);
7366 error = nfsv4_strtogid(nd, str, len, gidp);
7368 error = nfsv4_strtouid(nd, str, len, uidp);
7370 if (len > NFSV4_SMALLSTR)
7372 NFSCL_DEBUG(4, "eo nfsrv_parseug=%d\n", error);
7377 * Similar to nfsrpc_getlayout(), except that it uses nfsrpc_openlayget(),
7378 * so that it does both an Open and a Layoutget.
7381 nfsrpc_getopenlayout(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp,
7382 int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode,
7383 struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp,
7384 struct ucred *cred, NFSPROC_T *p)
7386 struct nfscllayout *lyp;
7387 struct nfsclflayout *flp;
7388 struct nfsclflayouthead flh;
7389 int error, islocked, layoutlen, recalled, retonclose, usecurstateid;
7390 int layouttype, laystat;
7391 nfsv4stateid_t stateid;
7392 struct nfsclsession *tsep;
7395 if (NFSHASFLEXFILE(nmp))
7396 layouttype = NFSLAYOUT_FLEXFILE;
7398 layouttype = NFSLAYOUT_NFSV4_1_FILES;
7400 * If lyp is returned non-NULL, there will be a refcnt (shared lock)
7401 * on it, iff flp != NULL or a lock (exclusive lock) on it iff
7404 lyp = nfscl_getlayout(nmp->nm_clp, newfhp, newfhlen, 0, &flp,
7406 NFSCL_DEBUG(4, "nfsrpc_getopenlayout nfscl_getlayout lyp=%p\n", lyp);
7409 else if (flp != NULL)
7413 if ((lyp == NULL || flp == NULL) && recalled == 0) {
7415 tsep = nfsmnt_mdssession(nmp);
7416 layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID +
7422 stateid.seqid = lyp->nfsly_stateid.seqid;
7423 stateid.other[0] = lyp->nfsly_stateid.other[0];
7424 stateid.other[1] = lyp->nfsly_stateid.other[1];
7425 stateid.other[2] = lyp->nfsly_stateid.other[2];
7427 error = nfsrpc_openlayoutrpc(nmp, vp, nfhp, fhlen,
7428 newfhp, newfhlen, mode, op, name, namelen,
7429 dpp, &stateid, usecurstateid, layouttype, layoutlen,
7430 &retonclose, &flh, &laystat, cred, p);
7431 NFSCL_DEBUG(4, "aft nfsrpc_openlayoutrpc laystat=%d err=%d\n",
7433 laystat = nfsrpc_layoutgetres(nmp, vp, newfhp, newfhlen,
7434 &stateid, retonclose, NULL, &lyp, &flh, layouttype, laystat,
7435 &islocked, cred, p);
7437 error = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp, newfhlen,
7438 mode, op, name, namelen, dpp, 0, 0, cred, p, 0, 0);
7440 nfscl_rellayout(lyp, 1);
7441 else if (islocked == 1)
7442 nfscl_rellayout(lyp, 0);
7447 * This function does an Open+LayoutGet for an NFSv4.1 mount with pNFS
7448 * enabled, only for the CLAIM_NULL case. All other NFSv4 Opens are
7449 * handled by nfsrpc_openrpc().
7450 * For the case where op == NULL, dvp is the directory. When op != NULL, it
7454 nfsrpc_openlayoutrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp,
7455 int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode,
7456 struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp,
7457 nfsv4stateid_t *stateidp, int usecurstateid, int layouttype,
7458 int layoutlen, int *retonclosep, struct nfsclflayouthead *flhp,
7459 int *laystatp, struct ucred *cred, NFSPROC_T *p)
7462 struct nfsrv_descript nfsd, *nd = &nfsd;
7463 struct nfscldeleg *ndp = NULL;
7464 struct nfsvattr nfsva;
7465 struct nfsclsession *tsep;
7466 uint32_t rflags, deleg;
7467 nfsattrbit_t attrbits;
7468 int error, ret, acesize, limitby, iomode;
7472 nfscl_reqstart(nd, NFSPROC_OPENLAYGET, nmp, nfhp, fhlen, NULL, NULL,
7474 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
7475 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
7476 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
7477 *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
7478 tsep = nfsmnt_mdssession(nmp);
7479 *tl++ = tsep->nfsess_clientid.lval[0];
7480 *tl = tsep->nfsess_clientid.lval[1];
7481 nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN);
7482 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
7483 *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE);
7484 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
7485 nfsm_strtom(nd, name, namelen);
7486 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
7487 *tl = txdr_unsigned(NFSV4OP_GETATTR);
7488 NFSZERO_ATTRBIT(&attrbits);
7489 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
7490 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY);
7491 nfsrv_putattrbit(nd, &attrbits);
7492 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
7493 *tl = txdr_unsigned(NFSV4OP_LAYOUTGET);
7494 if ((mode & NFSV4OPEN_ACCESSWRITE) != 0)
7495 iomode = NFSLAYOUTIOMODE_RW;
7497 iomode = NFSLAYOUTIOMODE_READ;
7498 nfsrv_setuplayoutget(nd, iomode, 0, UINT64_MAX, 0, stateidp,
7499 layouttype, layoutlen, usecurstateid);
7500 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
7501 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
7504 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
7505 if (nd->nd_repstat != 0)
7506 *laystatp = nd->nd_repstat;
7507 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
7508 /* ND_NOMOREDATA will be set if the Open operation failed. */
7509 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
7511 op->nfso_stateid.seqid = *tl++;
7512 op->nfso_stateid.other[0] = *tl++;
7513 op->nfso_stateid.other[1] = *tl++;
7514 op->nfso_stateid.other[2] = *tl;
7515 rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
7516 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
7519 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
7520 deleg = fxdr_unsigned(u_int32_t, *tl);
7521 if (deleg == NFSV4OPEN_DELEGATEREAD ||
7522 deleg == NFSV4OPEN_DELEGATEWRITE) {
7523 if (!(op->nfso_own->nfsow_clp->nfsc_flags &
7524 NFSCLFLAGS_FIRSTDELEG))
7525 op->nfso_own->nfsow_clp->nfsc_flags |=
7526 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
7527 ndp = malloc(sizeof(struct nfscldeleg) + newfhlen,
7528 M_NFSCLDELEG, M_WAITOK);
7529 LIST_INIT(&ndp->nfsdl_owner);
7530 LIST_INIT(&ndp->nfsdl_lock);
7531 ndp->nfsdl_clp = op->nfso_own->nfsow_clp;
7532 ndp->nfsdl_fhlen = newfhlen;
7533 NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen);
7534 newnfs_copyincred(cred, &ndp->nfsdl_cred);
7535 nfscl_lockinit(&ndp->nfsdl_rwlock);
7536 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
7538 ndp->nfsdl_stateid.seqid = *tl++;
7539 ndp->nfsdl_stateid.other[0] = *tl++;
7540 ndp->nfsdl_stateid.other[1] = *tl++;
7541 ndp->nfsdl_stateid.other[2] = *tl++;
7542 ret = fxdr_unsigned(int, *tl);
7543 if (deleg == NFSV4OPEN_DELEGATEWRITE) {
7544 ndp->nfsdl_flags = NFSCLDL_WRITE;
7546 * Indicates how much the file can grow.
7548 NFSM_DISSECT(tl, u_int32_t *,
7550 limitby = fxdr_unsigned(int, *tl++);
7552 case NFSV4OPEN_LIMITSIZE:
7553 ndp->nfsdl_sizelimit = fxdr_hyper(tl);
7555 case NFSV4OPEN_LIMITBLOCKS:
7556 ndp->nfsdl_sizelimit =
7557 fxdr_unsigned(u_int64_t, *tl++);
7558 ndp->nfsdl_sizelimit *=
7559 fxdr_unsigned(u_int64_t, *tl);
7562 error = NFSERR_BADXDR;
7566 ndp->nfsdl_flags = NFSCLDL_READ;
7568 ndp->nfsdl_flags |= NFSCLDL_RECALL;
7569 error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, &ret,
7573 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
7574 error = NFSERR_BADXDR;
7577 if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) != 0 ||
7578 nfscl_assumeposixlocks)
7579 op->nfso_posixlock = 1;
7581 op->nfso_posixlock = 0;
7582 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
7583 /* If the 2nd element == NFS_OK, the Getattr succeeded. */
7585 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
7586 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
7587 NULL, NULL, NULL, p, cred);
7591 ndp->nfsdl_change = nfsva.na_filerev;
7592 ndp->nfsdl_modtime = nfsva.na_mtime;
7593 ndp->nfsdl_flags |= NFSCLDL_MODTIMESET;
7598 * At this point, the Open has succeeded, so set
7599 * nd_repstat = NFS_OK. If the Layoutget failed,
7600 * this function just won't return a layout.
7602 if (nd->nd_repstat == 0) {
7603 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
7604 *laystatp = fxdr_unsigned(int, *++tl);
7605 if (*laystatp == 0) {
7606 error = nfsrv_parselayoutget(nmp, nd,
7607 stateidp, retonclosep, flhp);
7612 nd->nd_repstat = 0; /* Return 0 for Open. */
7615 if (nd->nd_repstat != 0 && error == 0)
7616 error = nd->nd_repstat;
7618 free(ndp, M_NFSCLDELEG);
7619 mbuf_freem(nd->nd_mrep);
7624 * Similar nfsrpc_createv4(), but also does the LayoutGet operation.
7625 * Used only for mounts with pNFS enabled.
7628 nfsrpc_createlayout(vnode_t dvp, char *name, int namelen, struct vattr *vap,
7629 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp,
7630 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
7631 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
7632 int *dattrflagp, void *dstuff, int *unlockedp, nfsv4stateid_t *stateidp,
7633 int usecurstateid, int layouttype, int layoutlen, int *retonclosep,
7634 struct nfsclflayouthead *flhp, int *laystatp)
7637 int error = 0, deleg, newone, ret, acesize, limitby;
7638 struct nfsrv_descript nfsd, *nd = &nfsd;
7639 struct nfsclopen *op;
7640 struct nfscldeleg *dp = NULL;
7643 struct nfsclsession *tsep;
7644 nfsattrbit_t attrbits;
7645 nfsv4stateid_t stateid;
7646 struct nfsmount *nmp;
7648 nmp = VFSTONFS(dvp->v_mount);
7656 if (namelen > NFS_MAXNAMLEN)
7657 return (ENAMETOOLONG);
7658 NFSCL_REQSTART(nd, NFSPROC_CREATELAYGET, dvp);
7660 * For V4, this is actually an Open op.
7662 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
7663 *tl++ = txdr_unsigned(owp->nfsow_seqid);
7664 *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
7665 NFSV4OPEN_ACCESSREAD);
7666 *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE);
7667 tsep = nfsmnt_mdssession(nmp);
7668 *tl++ = tsep->nfsess_clientid.lval[0];
7669 *tl = tsep->nfsess_clientid.lval[1];
7670 nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN);
7671 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
7672 *tl++ = txdr_unsigned(NFSV4OPEN_CREATE);
7673 if ((fmode & O_EXCL) != 0) {
7674 if (NFSHASSESSPERSIST(nmp)) {
7675 /* Use GUARDED for persistent sessions. */
7676 *tl = txdr_unsigned(NFSCREATE_GUARDED);
7677 nfscl_fillsattr(nd, vap, dvp, 0, 0);
7679 /* Otherwise, use EXCLUSIVE4_1. */
7680 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41);
7681 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
7682 *tl++ = cverf.lval[0];
7683 *tl = cverf.lval[1];
7684 nfscl_fillsattr(nd, vap, dvp, 0, 0);
7687 *tl = txdr_unsigned(NFSCREATE_UNCHECKED);
7688 nfscl_fillsattr(nd, vap, dvp, 0, 0);
7690 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
7691 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
7692 nfsm_strtom(nd, name, namelen);
7693 /* Get the new file's handle and attributes, plus save the FH. */
7694 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
7695 *tl++ = txdr_unsigned(NFSV4OP_SAVEFH);
7696 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
7697 *tl = txdr_unsigned(NFSV4OP_GETATTR);
7698 NFSGETATTR_ATTRBIT(&attrbits);
7699 nfsrv_putattrbit(nd, &attrbits);
7700 /* Get the directory's post-op attributes. */
7701 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
7702 *tl = txdr_unsigned(NFSV4OP_PUTFH);
7703 nfsm_fhtom(nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0);
7704 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
7705 *tl = txdr_unsigned(NFSV4OP_GETATTR);
7706 nfsrv_putattrbit(nd, &attrbits);
7707 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
7708 *tl++ = txdr_unsigned(NFSV4OP_RESTOREFH);
7709 *tl = txdr_unsigned(NFSV4OP_LAYOUTGET);
7710 nfsrv_setuplayoutget(nd, NFSLAYOUTIOMODE_RW, 0, UINT64_MAX, 0, stateidp,
7711 layouttype, layoutlen, usecurstateid);
7712 error = nfscl_request(nd, dvp, p, cred, dstuff);
7715 NFSCL_DEBUG(4, "nfsrpc_createlayout stat=%d err=%d\n", nd->nd_repstat,
7717 if (nd->nd_repstat != 0)
7718 *laystatp = nd->nd_repstat;
7719 NFSCL_INCRSEQID(owp->nfsow_seqid, nd);
7720 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
7721 NFSCL_DEBUG(4, "nfsrpc_createlayout open succeeded\n");
7722 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
7724 stateid.seqid = *tl++;
7725 stateid.other[0] = *tl++;
7726 stateid.other[1] = *tl++;
7727 stateid.other[2] = *tl;
7728 nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
7729 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
7730 deleg = fxdr_unsigned(int, *tl);
7731 if (deleg == NFSV4OPEN_DELEGATEREAD ||
7732 deleg == NFSV4OPEN_DELEGATEWRITE) {
7733 if (!(owp->nfsow_clp->nfsc_flags &
7734 NFSCLFLAGS_FIRSTDELEG))
7735 owp->nfsow_clp->nfsc_flags |=
7736 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
7737 dp = malloc(sizeof(struct nfscldeleg) + NFSX_V4FHMAX,
7738 M_NFSCLDELEG, M_WAITOK);
7739 LIST_INIT(&dp->nfsdl_owner);
7740 LIST_INIT(&dp->nfsdl_lock);
7741 dp->nfsdl_clp = owp->nfsow_clp;
7742 newnfs_copyincred(cred, &dp->nfsdl_cred);
7743 nfscl_lockinit(&dp->nfsdl_rwlock);
7744 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
7746 dp->nfsdl_stateid.seqid = *tl++;
7747 dp->nfsdl_stateid.other[0] = *tl++;
7748 dp->nfsdl_stateid.other[1] = *tl++;
7749 dp->nfsdl_stateid.other[2] = *tl++;
7750 ret = fxdr_unsigned(int, *tl);
7751 if (deleg == NFSV4OPEN_DELEGATEWRITE) {
7752 dp->nfsdl_flags = NFSCLDL_WRITE;
7754 * Indicates how much the file can grow.
7756 NFSM_DISSECT(tl, u_int32_t *,
7758 limitby = fxdr_unsigned(int, *tl++);
7760 case NFSV4OPEN_LIMITSIZE:
7761 dp->nfsdl_sizelimit = fxdr_hyper(tl);
7763 case NFSV4OPEN_LIMITBLOCKS:
7764 dp->nfsdl_sizelimit =
7765 fxdr_unsigned(u_int64_t, *tl++);
7766 dp->nfsdl_sizelimit *=
7767 fxdr_unsigned(u_int64_t, *tl);
7770 error = NFSERR_BADXDR;
7774 dp->nfsdl_flags = NFSCLDL_READ;
7777 dp->nfsdl_flags |= NFSCLDL_RECALL;
7778 error = nfsrv_dissectace(nd, &dp->nfsdl_ace, &ret,
7782 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
7783 error = NFSERR_BADXDR;
7787 /* Now, we should have the status for the SaveFH. */
7788 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
7790 NFSCL_DEBUG(4, "nfsrpc_createlayout SaveFH ok\n");
7792 * Now, process the GetFH and Getattr for the newly
7793 * created file. nfscl_mtofh() will set
7794 * ND_NOMOREDATA if these weren't successful.
7796 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
7797 NFSCL_DEBUG(4, "aft nfscl_mtofh err=%d\n", error);
7801 nd->nd_flag |= ND_NOMOREDATA;
7802 /* Now we have the PutFH and Getattr for the directory. */
7803 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
7804 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
7806 nd->nd_flag |= ND_NOMOREDATA;
7808 NFSM_DISSECT(tl, uint32_t *, 2 *
7811 nd->nd_flag |= ND_NOMOREDATA;
7814 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
7815 /* Load the directory attributes. */
7816 error = nfsm_loadattr(nd, dnap);
7817 NFSCL_DEBUG(4, "aft nfsm_loadattr err=%d\n", error);
7821 if (dp != NULL && *attrflagp != 0) {
7822 dp->nfsdl_change = nnap->na_filerev;
7823 dp->nfsdl_modtime = nnap->na_mtime;
7824 dp->nfsdl_flags |= NFSCLDL_MODTIMESET;
7827 * We can now complete the Open state.
7831 dp->nfsdl_fhlen = nfhp->nfh_len;
7832 NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh,
7836 * Get an Open structure that will be
7837 * attached to the OpenOwner, acquired already.
7839 error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len,
7840 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0,
7841 cred, p, NULL, &op, &newone, NULL, 0);
7844 op->nfso_stateid = stateid;
7845 newnfs_copyincred(cred, &op->nfso_cred);
7847 nfscl_openrelease(nmp, op, error, newone);
7850 /* Now, handle the RestoreFH and LayoutGet. */
7851 if (nd->nd_repstat == 0) {
7852 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
7853 *laystatp = fxdr_unsigned(int, *(tl + 3));
7854 if (*laystatp == 0) {
7855 error = nfsrv_parselayoutget(nmp, nd,
7856 stateidp, retonclosep, flhp);
7860 NFSCL_DEBUG(4, "aft nfsrv_parselayout err=%d\n",
7866 if (nd->nd_repstat != 0 && error == 0)
7867 error = nd->nd_repstat;
7868 if (error == NFSERR_STALECLIENTID || error == NFSERR_BADSESSION)
7869 nfscl_initiate_recovery(owp->nfsow_clp);
7871 NFSCL_DEBUG(4, "eo nfsrpc_createlayout err=%d\n", error);
7875 free(dp, M_NFSCLDELEG);
7876 mbuf_freem(nd->nd_mrep);
7881 * Similar to nfsrpc_getopenlayout(), except that it used for the Create case.
7884 nfsrpc_getcreatelayout(vnode_t dvp, char *name, int namelen, struct vattr *vap,
7885 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp,
7886 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
7887 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
7888 int *dattrflagp, void *dstuff, int *unlockedp)
7890 struct nfscllayout *lyp;
7891 struct nfsclflayouthead flh;
7893 struct nfsclsession *tsep;
7894 struct nfsmount *nmp;
7895 nfsv4stateid_t stateid;
7896 int error, layoutlen, layouttype, retonclose, laystat;
7899 nmp = VFSTONFS(dvp->v_mount);
7900 if (NFSHASFLEXFILE(nmp))
7901 layouttype = NFSLAYOUT_FLEXFILE;
7903 layouttype = NFSLAYOUT_NFSV4_1_FILES;
7905 tsep = nfsmnt_mdssession(nmp);
7906 layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID + 3 * NFSX_UNSIGNED);
7907 error = nfsrpc_createlayout(dvp, name, namelen, vap, cverf, fmode,
7908 owp, dpp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp,
7909 dstuff, unlockedp, &stateid, 1, layouttype, layoutlen, &retonclose,
7911 NFSCL_DEBUG(4, "aft nfsrpc_createlayoutrpc laystat=%d err=%d\n",
7916 laystat = nfsrpc_layoutgetres(nmp, dvp, nfhp->nfh_fh,
7917 nfhp->nfh_len, &stateid, retonclose, NULL, &lyp, &flh,
7918 layouttype, laystat, NULL, cred, p);
7920 laystat = nfsrpc_layoutgetres(nmp, dvp, NULL, 0, &stateid,
7921 retonclose, NULL, &lyp, &flh, layouttype, laystat, NULL,
7924 nfscl_rellayout(lyp, 0);
7929 * Process the results of a layoutget() operation.
7932 nfsrpc_layoutgetres(struct nfsmount *nmp, vnode_t vp, uint8_t *newfhp,
7933 int newfhlen, nfsv4stateid_t *stateidp, int retonclose, uint32_t *notifybit,
7934 struct nfscllayout **lypp, struct nfsclflayouthead *flhp, int layouttype,
7935 int laystat, int *islockedp, struct ucred *cred, NFSPROC_T *p)
7937 struct nfsclflayout *tflp;
7938 struct nfscldevinfo *dip;
7942 if (laystat == NFSERR_UNKNLAYOUTTYPE) {
7944 if (!NFSHASFLEXFILE(nmp)) {
7945 /* Switch to using Flex File Layout. */
7946 nmp->nm_state |= NFSSTA_FLEXFILE;
7947 } else if (layouttype == NFSLAYOUT_FLEXFILE) {
7949 NFSCL_DEBUG(1, "disable PNFS\n");
7950 nmp->nm_state &= ~(NFSSTA_PNFS | NFSSTA_FLEXFILE);
7955 NFSCL_DEBUG(4, "nfsrpc_layoutgetres at FOREACH\n");
7956 LIST_FOREACH(tflp, flhp, nfsfl_list) {
7957 if (layouttype == NFSLAYOUT_FLEXFILE)
7958 mirrorcnt = tflp->nfsfl_mirrorcnt;
7961 for (i = 0; i < mirrorcnt; i++) {
7962 laystat = nfscl_adddevinfo(nmp, NULL, i, tflp);
7963 NFSCL_DEBUG(4, "aft adddev=%d\n", laystat);
7965 if (layouttype == NFSLAYOUT_FLEXFILE)
7966 dev = tflp->nfsfl_ffm[i].dev;
7968 dev = tflp->nfsfl_dev;
7969 laystat = nfsrpc_getdeviceinfo(nmp, dev,
7970 layouttype, notifybit, &dip, cred,
7972 NFSCL_DEBUG(4, "aft nfsrpc_gdi=%d\n",
7976 laystat = nfscl_adddevinfo(nmp, dip, i,
7979 printf("nfsrpc_layoutgetresout"
7988 * nfscl_layout() always returns with the nfsly_lock
7989 * set to a refcnt (shared lock).
7990 * Passing in dvp is sufficient, since it is only used to
7991 * get the fsid for the file system.
7993 laystat = nfscl_layout(nmp, vp, newfhp, newfhlen, stateidp,
7994 layouttype, retonclose, flhp, lypp, cred, p);
7995 NFSCL_DEBUG(4, "nfsrpc_layoutgetres: aft nfscl_layout=%d\n",
7997 if (laystat == 0 && islockedp != NULL)
8004 * nfs copy_file_range operation.
8007 nfsrpc_copy_file_range(vnode_t invp, off_t *inoffp, vnode_t outvp,
8008 off_t *outoffp, size_t *lenp, unsigned int flags, int *inattrflagp,
8009 struct nfsvattr *innap, int *outattrflagp, struct nfsvattr *outnap,
8010 struct ucred *cred, bool consecutive, bool *must_commitp)
8012 int commit, error, expireret = 0, retrycnt;
8013 u_int32_t clidrev = 0;
8014 struct nfsmount *nmp = VFSTONFS(vnode_mount(invp));
8015 struct nfsfh *innfhp = NULL, *outnfhp = NULL;
8016 nfsv4stateid_t instateid, outstateid;
8017 void *inlckp, *outlckp;
8019 if (nmp->nm_clp != NULL)
8020 clidrev = nmp->nm_clp->nfsc_clientidrev;
8021 innfhp = VTONFS(invp)->n_fhp;
8022 outnfhp = VTONFS(outvp)->n_fhp;
8025 /* Get both stateids. */
8027 nfscl_getstateid(invp, innfhp->nfh_fh, innfhp->nfh_len,
8028 NFSV4OPEN_ACCESSREAD, 0, NULL, curthread, &instateid,
8031 nfscl_getstateid(outvp, outnfhp->nfh_fh, outnfhp->nfh_len,
8032 NFSV4OPEN_ACCESSWRITE, 0, NULL, curthread, &outstateid,
8035 error = nfsrpc_copyrpc(invp, *inoffp, outvp, *outoffp, lenp,
8036 &instateid, &outstateid, innap, inattrflagp, outnap,
8037 outattrflagp, consecutive, &commit, cred, curthread);
8039 if (commit != NFSWRITE_FILESYNC)
8040 *must_commitp = true;
8043 } else if (error == NFSERR_STALESTATEID)
8044 nfscl_initiate_recovery(nmp->nm_clp);
8046 nfscl_lockderef(inlckp);
8047 if (outlckp != NULL)
8048 nfscl_lockderef(outlckp);
8049 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
8050 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
8051 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
8052 (void) nfs_catnap(PZERO, error, "nfs_cfr");
8053 } else if ((error == NFSERR_EXPIRED ||
8054 error == NFSERR_BADSTATEID) && clidrev != 0) {
8055 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev,
8059 } while (error == NFSERR_GRACE || error == NFSERR_DELAY ||
8060 error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION ||
8061 error == NFSERR_STALEDONTRECOVER ||
8062 (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
8063 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
8064 expireret == 0 && clidrev != 0 && retrycnt < 4));
8065 if (error != 0 && (retrycnt >= 4 ||
8066 error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION ||
8067 error == NFSERR_STALEDONTRECOVER))
8076 nfsrpc_copyrpc(vnode_t invp, off_t inoff, vnode_t outvp, off_t outoff,
8077 size_t *lenp, nfsv4stateid_t *instateidp, nfsv4stateid_t *outstateidp,
8078 struct nfsvattr *innap, int *inattrflagp, struct nfsvattr *outnap,
8079 int *outattrflagp, bool consecutive, int *commitp, struct ucred *cred,
8084 struct nfsrv_descript nfsd;
8085 struct nfsrv_descript *nd = &nfsd;
8086 struct nfsmount *nmp;
8087 nfsattrbit_t attrbits;
8090 nmp = VFSTONFS(outvp->v_mount);
8091 *inattrflagp = *outattrflagp = 0;
8092 *commitp = NFSWRITE_UNSTABLE;
8095 if (len > nfs_maxcopyrange)
8096 len = nfs_maxcopyrange;
8097 NFSCL_REQSTART(nd, NFSPROC_COPY, invp);
8098 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
8099 *tl = txdr_unsigned(NFSV4OP_GETATTR);
8100 NFSGETATTR_ATTRBIT(&attrbits);
8101 nfsrv_putattrbit(nd, &attrbits);
8102 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
8103 *tl = txdr_unsigned(NFSV4OP_PUTFH);
8104 nfsm_fhtom(nd, VTONFS(outvp)->n_fhp->nfh_fh,
8105 VTONFS(outvp)->n_fhp->nfh_len, 0);
8106 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
8107 *tl = txdr_unsigned(NFSV4OP_COPY);
8108 nfsm_stateidtom(nd, instateidp, NFSSTATEID_PUTSTATEID);
8109 nfsm_stateidtom(nd, outstateidp, NFSSTATEID_PUTSTATEID);
8110 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_HYPER + 4 * NFSX_UNSIGNED);
8111 txdr_hyper(inoff, tl); tl += 2;
8112 txdr_hyper(outoff, tl); tl += 2;
8113 txdr_hyper(len, tl); tl += 2;
8115 *tl++ = newnfs_true;
8117 *tl++ = newnfs_false;
8118 *tl++ = newnfs_true;
8120 *tl = txdr_unsigned(NFSV4OP_GETATTR);
8121 NFSWRITEGETATTR_ATTRBIT(&attrbits);
8122 nfsrv_putattrbit(nd, &attrbits);
8123 error = nfscl_request(nd, invp, p, cred, NULL);
8126 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
8127 /* Get the input file's attributes. */
8128 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
8129 if (*(tl + 1) == 0) {
8130 error = nfsm_loadattr(nd, innap);
8135 nd->nd_flag |= ND_NOMOREDATA;
8137 /* Skip over return stat for PutFH. */
8138 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
8139 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
8141 nd->nd_flag |= ND_NOMOREDATA;
8143 /* Skip over return stat for Copy. */
8144 if ((nd->nd_flag & ND_NOMOREDATA) == 0)
8145 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
8146 if (nd->nd_repstat == 0) {
8147 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
8149 /* There should be no callback ids. */
8150 error = NFSERR_BADXDR;
8153 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED +
8155 len = fxdr_hyper(tl); tl += 2;
8156 *commitp = fxdr_unsigned(int, *tl++);
8158 if (!NFSHASWRITEVERF(nmp)) {
8159 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
8160 NFSSETWRITEVERF(nmp);
8161 } else if (NFSBCMP(tl, nmp->nm_verf, NFSX_VERF)) {
8162 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
8163 nd->nd_repstat = NFSERR_STALEWRITEVERF;
8166 tl += (NFSX_VERF / NFSX_UNSIGNED);
8167 if (nd->nd_repstat == 0 && *++tl != newnfs_true)
8168 /* Must be a synchronous copy. */
8169 nd->nd_repstat = NFSERR_NOTSUPP;
8170 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
8171 error = nfsm_loadattr(nd, outnap);
8173 *outattrflagp = NFS_LATTR_NOSHRINK;
8174 if (nd->nd_repstat == 0)
8176 } else if (nd->nd_repstat == NFSERR_OFFLOADNOREQS) {
8178 * For the case where consecutive is not supported, but
8179 * synchronous is supported, we can try consecutive == false
8180 * by returning this error. Otherwise, return NFSERR_NOTSUPP,
8181 * since Copy cannot be done.
8183 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
8184 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
8185 if (!consecutive || *++tl == newnfs_false)
8186 nd->nd_repstat = NFSERR_NOTSUPP;
8188 nd->nd_repstat = NFSERR_BADXDR;
8191 error = nd->nd_repstat;
8193 mbuf_freem(nd->nd_mrep);
8201 nfsrpc_seek(vnode_t vp, off_t *offp, bool *eofp, int content,
8202 struct ucred *cred, struct nfsvattr *nap, int *attrflagp)
8204 int error, expireret = 0, retrycnt;
8205 u_int32_t clidrev = 0;
8206 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
8207 struct nfsnode *np = VTONFS(vp);
8208 struct nfsfh *nfhp = NULL;
8209 nfsv4stateid_t stateid;
8212 if (nmp->nm_clp != NULL)
8213 clidrev = nmp->nm_clp->nfsc_clientidrev;
8218 nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
8219 NFSV4OPEN_ACCESSREAD, 0, cred, curthread, &stateid, &lckp);
8220 error = nfsrpc_seekrpc(vp, offp, &stateid, eofp, content,
8221 nap, attrflagp, cred);
8222 if (error == NFSERR_STALESTATEID)
8223 nfscl_initiate_recovery(nmp->nm_clp);
8225 nfscl_lockderef(lckp);
8226 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
8227 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
8228 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
8229 (void) nfs_catnap(PZERO, error, "nfs_seek");
8230 } else if ((error == NFSERR_EXPIRED ||
8231 error == NFSERR_BADSTATEID) && clidrev != 0) {
8232 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev,
8236 } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
8237 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
8238 error == NFSERR_BADSESSION ||
8239 (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
8240 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
8241 expireret == 0 && clidrev != 0 && retrycnt < 4) ||
8242 (error == NFSERR_OPENMODE && retrycnt < 4));
8243 if (error && retrycnt >= 4)
8252 nfsrpc_seekrpc(vnode_t vp, off_t *offp, nfsv4stateid_t *stateidp, bool *eofp,
8253 int content, struct nfsvattr *nap, int *attrflagp, struct ucred *cred)
8257 struct nfsrv_descript nfsd;
8258 struct nfsrv_descript *nd = &nfsd;
8259 nfsattrbit_t attrbits;
8262 NFSCL_REQSTART(nd, NFSPROC_SEEK, vp);
8263 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
8264 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
8265 txdr_hyper(*offp, tl); tl += 2;
8266 *tl++ = txdr_unsigned(content);
8267 *tl = txdr_unsigned(NFSV4OP_GETATTR);
8268 NFSGETATTR_ATTRBIT(&attrbits);
8269 nfsrv_putattrbit(nd, &attrbits);
8270 error = nfscl_request(nd, vp, curthread, cred, NULL);
8273 if (nd->nd_repstat == 0) {
8274 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_HYPER);
8275 if (*tl++ == newnfs_true)
8279 *offp = fxdr_hyper(tl);
8280 /* Just skip over Getattr op status. */
8281 error = nfsm_loadattr(nd, nap);
8285 error = nd->nd_repstat;
8287 mbuf_freem(nd->nd_mrep);
8292 * The getextattr RPC.
8295 nfsrpc_getextattr(vnode_t vp, const char *name, struct uio *uiop, ssize_t *lenp,
8296 struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p)
8300 struct nfsrv_descript nfsd;
8301 struct nfsrv_descript *nd = &nfsd;
8302 nfsattrbit_t attrbits;
8306 NFSCL_REQSTART(nd, NFSPROC_GETEXTATTR, vp);
8307 nfsm_strtom(nd, name, strlen(name));
8308 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
8309 *tl = txdr_unsigned(NFSV4OP_GETATTR);
8310 NFSGETATTR_ATTRBIT(&attrbits);
8311 nfsrv_putattrbit(nd, &attrbits);
8312 error = nfscl_request(nd, vp, p, cred, NULL);
8315 if (nd->nd_repstat == 0) {
8316 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
8317 len = fxdr_unsigned(uint32_t, *tl);
8318 /* Sanity check lengths. */
8319 if (uiop != NULL && len > 0 && len <= IOSIZE_MAX &&
8320 uiop->uio_resid <= UINT32_MAX) {
8321 len2 = uiop->uio_resid;
8323 error = nfsm_mbufuio(nd, uiop, len);
8325 error = nfsm_mbufuio(nd, uiop, len2);
8328 * nfsm_mbufuio() advances to a multiple
8329 * of 4, so round up len2 as well. Then
8330 * we need to advance over the rest of
8331 * the data, rounding up the remaining
8334 len2 = NFSM_RNDUP(len2);
8335 len2 = NFSM_RNDUP(len - len2);
8337 error = nfsm_advance(nd, len2,
8341 } else if (uiop == NULL && len > 0) {
8342 /* Just wants the length and not the data. */
8343 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
8349 /* Just skip over Getattr op status. */
8350 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
8351 error = nfsm_loadattr(nd, nap);
8356 error = nd->nd_repstat;
8358 mbuf_freem(nd->nd_mrep);
8363 * The setextattr RPC.
8366 nfsrpc_setextattr(vnode_t vp, const char *name, struct uio *uiop,
8367 struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p)
8371 struct nfsrv_descript nfsd;
8372 struct nfsrv_descript *nd = &nfsd;
8373 nfsattrbit_t attrbits;
8376 NFSCL_REQSTART(nd, NFSPROC_SETEXTATTR, vp);
8377 if (uiop->uio_resid > nd->nd_maxreq) {
8378 /* nd_maxreq is set by NFSCL_REQSTART(). */
8379 mbuf_freem(nd->nd_mreq);
8382 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
8383 *tl = txdr_unsigned(NFSV4SXATTR_EITHER);
8384 nfsm_strtom(nd, name, strlen(name));
8385 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
8386 *tl = txdr_unsigned(uiop->uio_resid);
8387 nfsm_uiombuf(nd, uiop, uiop->uio_resid);
8388 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
8389 *tl = txdr_unsigned(NFSV4OP_GETATTR);
8390 NFSGETATTR_ATTRBIT(&attrbits);
8391 nfsrv_putattrbit(nd, &attrbits);
8392 error = nfscl_request(nd, vp, p, cred, NULL);
8395 if (nd->nd_repstat == 0) {
8396 /* Just skip over the reply and Getattr op status. */
8397 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + 3 *
8399 error = nfsm_loadattr(nd, nap);
8404 error = nd->nd_repstat;
8406 mbuf_freem(nd->nd_mrep);
8411 * The removeextattr RPC.
8414 nfsrpc_rmextattr(vnode_t vp, const char *name, struct nfsvattr *nap,
8415 int *attrflagp, struct ucred *cred, NFSPROC_T *p)
8419 struct nfsrv_descript nfsd;
8420 struct nfsrv_descript *nd = &nfsd;
8421 nfsattrbit_t attrbits;
8424 NFSCL_REQSTART(nd, NFSPROC_RMEXTATTR, vp);
8425 nfsm_strtom(nd, name, strlen(name));
8426 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
8427 *tl = txdr_unsigned(NFSV4OP_GETATTR);
8428 NFSGETATTR_ATTRBIT(&attrbits);
8429 nfsrv_putattrbit(nd, &attrbits);
8430 error = nfscl_request(nd, vp, p, cred, NULL);
8433 if (nd->nd_repstat == 0) {
8434 /* Just skip over the reply and Getattr op status. */
8435 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + 2 *
8437 error = nfsm_loadattr(nd, nap);
8442 error = nd->nd_repstat;
8444 mbuf_freem(nd->nd_mrep);
8449 * The listextattr RPC.
8452 nfsrpc_listextattr(vnode_t vp, uint64_t *cookiep, struct uio *uiop,
8453 size_t *lenp, bool *eofp, struct nfsvattr *nap, int *attrflagp,
8454 struct ucred *cred, NFSPROC_T *p)
8457 int cnt, error, i, len;
8458 struct nfsrv_descript nfsd;
8459 struct nfsrv_descript *nd = &nfsd;
8460 nfsattrbit_t attrbits;
8464 NFSCL_REQSTART(nd, NFSPROC_LISTEXTATTR, vp);
8465 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
8466 txdr_hyper(*cookiep, tl); tl += 2;
8467 *tl++ = txdr_unsigned(*lenp);
8468 *tl = txdr_unsigned(NFSV4OP_GETATTR);
8469 NFSGETATTR_ATTRBIT(&attrbits);
8470 nfsrv_putattrbit(nd, &attrbits);
8471 error = nfscl_request(nd, vp, p, cred, NULL);
8476 if (nd->nd_repstat == 0) {
8477 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
8478 *cookiep = fxdr_hyper(tl); tl += 2;
8479 cnt = fxdr_unsigned(int, *tl);
8484 for (i = 0; i < cnt; i++) {
8485 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
8486 len = fxdr_unsigned(int, *tl);
8487 if (len <= 0 || len > EXTATTR_MAXNAMELEN) {
8492 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
8493 else if (uiop->uio_resid >= len + 1) {
8495 error = uiomove(&c, sizeof(c), uiop);
8497 error = nfsm_mbufuio(nd, uiop, len);
8499 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
8506 /* Get the eof and skip over the Getattr op status. */
8507 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED);
8509 * *eofp is set false above, because it wasn't able to copy
8512 if (*eofp && *tl == 0)
8514 error = nfsm_loadattr(nd, nap);
8519 error = nd->nd_repstat;
8521 mbuf_freem(nd->nd_mrep);