2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
38 * Rpc op calls, generally called from the vnode op calls or through the
39 * buffer cache, for NFS v2, 3 and 4.
40 * These do not normally make any changes to vnode arguments or use
41 * structures that might change between the VFS variants. The returned
42 * arguments are all at the end, after the NFSPROC_T *p one.
46 #include "opt_inet6.h"
48 #include <fs/nfs/nfsport.h>
49 #include <sys/sysctl.h>
51 SYSCTL_DECL(_vfs_nfs);
53 static int nfsignore_eexist = 0;
54 SYSCTL_INT(_vfs_nfs, OID_AUTO, ignore_eexist, CTLFLAG_RW,
55 &nfsignore_eexist, 0, "NFS ignore EEXIST replies for mkdir/symlink");
60 extern int nfs_numnfscbd;
61 extern struct timeval nfsboottime;
62 extern u_int32_t newnfs_false, newnfs_true;
63 extern nfstype nfsv34_type[9];
64 extern int nfsrv_useacl;
65 extern char nfsv4_callbackaddr[INET6_ADDRSTRLEN];
66 extern int nfscl_debuglevel;
68 int nfstest_outofseq = 0;
69 int nfscl_assumeposixlocks = 1;
70 int nfscl_enablecallb = 0;
71 short nfsv4_cbport = NFSV4_CBPORT;
72 int nfstest_openallsetattr = 0;
73 #endif /* !APPLEKEXT */
75 #define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1))
78 * nfscl_getsameserver() can return one of three values:
79 * NFSDSP_USETHISSESSION - Use this session for the DS.
80 * NFSDSP_SEQTHISSESSION - Use the nfsclds_sequence field of this dsp for new
82 * NFSDSP_NOTFOUND - No matching server was found.
85 NFSDSP_USETHISSESSION = 0,
86 NFSDSP_SEQTHISSESSION = 1,
90 static int nfsrpc_setattrrpc(vnode_t , struct vattr *, nfsv4stateid_t *,
91 struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, void *);
92 static int nfsrpc_readrpc(vnode_t , struct uio *, struct ucred *,
93 nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *, void *);
94 static int nfsrpc_writerpc(vnode_t , struct uio *, int *, int *,
95 struct ucred *, nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *,
97 static int nfsrpc_createv23(vnode_t , char *, int, struct vattr *,
98 nfsquad_t, int, struct ucred *, NFSPROC_T *, struct nfsvattr *,
99 struct nfsvattr *, struct nfsfh **, int *, int *, void *);
100 static int nfsrpc_createv4(vnode_t , char *, int, struct vattr *,
101 nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, struct ucred *,
102 NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, struct nfsfh **, int *,
103 int *, void *, int *);
104 static int nfsrpc_locku(struct nfsrv_descript *, struct nfsmount *,
105 struct nfscllockowner *, u_int64_t, u_int64_t,
106 u_int32_t, struct ucred *, NFSPROC_T *, int);
107 static int nfsrpc_setaclrpc(vnode_t, struct ucred *, NFSPROC_T *,
108 struct acl *, nfsv4stateid_t *, void *);
109 static int nfsrpc_getlayout(struct nfsmount *, vnode_t, struct nfsfh *, int,
110 uint32_t *, nfsv4stateid_t *, uint64_t, struct nfscllayout **,
111 struct ucred *, NFSPROC_T *);
112 static int nfsrpc_fillsa(struct nfsmount *, struct sockaddr_storage *,
113 struct nfsclds **, NFSPROC_T *);
114 static void nfscl_initsessionslots(struct nfsclsession *);
115 static int nfscl_doflayoutio(vnode_t, struct uio *, int *, int *, int *,
116 nfsv4stateid_t *, int, struct nfscldevinfo *, struct nfscllayout *,
117 struct nfsclflayout *, uint64_t, uint64_t, struct ucred *, NFSPROC_T *);
118 static int nfsrpc_readds(vnode_t, struct uio *, nfsv4stateid_t *, int *,
119 struct nfsclds *, uint64_t, int, struct nfsfh *, struct ucred *,
121 static int nfsrpc_writeds(vnode_t, struct uio *, int *, int *,
122 nfsv4stateid_t *, struct nfsclds *, uint64_t, int,
123 struct nfsfh *, int, struct ucred *, NFSPROC_T *);
124 static enum nfsclds_state nfscl_getsameserver(struct nfsmount *,
125 struct nfsclds *, struct nfsclds **);
127 static int nfsrpc_commitds(vnode_t, uint64_t, int, struct nfsclds *,
128 struct nfsfh *, struct ucred *, NFSPROC_T *, void *);
132 * nfs null call from vfs.
135 nfsrpc_null(vnode_t vp, struct ucred *cred, NFSPROC_T *p)
138 struct nfsrv_descript nfsd, *nd = &nfsd;
140 NFSCL_REQSTART(nd, NFSPROC_NULL, vp);
141 error = nfscl_request(nd, vp, p, cred, NULL);
142 if (nd->nd_repstat && !error)
143 error = nd->nd_repstat;
144 mbuf_freem(nd->nd_mrep);
150 * For nfs version 3 and 4, use the access rpc to check accessibility. If file
151 * modes are changed on the server, accesses might still fail later.
154 nfsrpc_access(vnode_t vp, int acmode, struct ucred *cred,
155 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp)
158 u_int32_t mode, rmode;
161 mode = NFSACCESS_READ;
164 if (vnode_vtype(vp) == VDIR) {
166 mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND |
169 mode |= NFSACCESS_LOOKUP;
172 mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND);
174 mode |= NFSACCESS_EXECUTE;
178 * Now, just call nfsrpc_accessrpc() to do the actual RPC.
180 error = nfsrpc_accessrpc(vp, mode, cred, p, nap, attrflagp, &rmode,
184 * The NFS V3 spec does not clarify whether or not
185 * the returned access bits can be a superset of
186 * the ones requested, so...
188 if (!error && (rmode & mode) != mode)
194 * The actual rpc, separated out for Darwin.
197 nfsrpc_accessrpc(vnode_t vp, u_int32_t mode, struct ucred *cred,
198 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, u_int32_t *rmodep,
202 u_int32_t supported, rmode;
204 struct nfsrv_descript nfsd, *nd = &nfsd;
205 nfsattrbit_t attrbits;
209 NFSCL_REQSTART(nd, NFSPROC_ACCESS, vp);
210 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
211 *tl = txdr_unsigned(mode);
212 if (nd->nd_flag & ND_NFSV4) {
214 * And do a Getattr op.
216 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
217 *tl = txdr_unsigned(NFSV4OP_GETATTR);
218 NFSGETATTR_ATTRBIT(&attrbits);
219 (void) nfsrv_putattrbit(nd, &attrbits);
221 error = nfscl_request(nd, vp, p, cred, stuff);
224 if (nd->nd_flag & ND_NFSV3) {
225 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
229 if (!nd->nd_repstat) {
230 if (nd->nd_flag & ND_NFSV4) {
231 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
232 supported = fxdr_unsigned(u_int32_t, *tl++);
234 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
236 rmode = fxdr_unsigned(u_int32_t, *tl);
237 if (nd->nd_flag & ND_NFSV4)
238 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
241 * It's not obvious what should be done about
242 * unsupported access modes. For now, be paranoid
243 * and clear the unsupported ones.
248 error = nd->nd_repstat;
250 mbuf_freem(nd->nd_mrep);
258 nfsrpc_open(vnode_t vp, int amode, struct ucred *cred, NFSPROC_T *p)
260 struct nfsclopen *op;
261 struct nfscldeleg *dp;
263 struct nfsnode *np = VTONFS(vp);
264 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
265 u_int32_t mode, clidrev;
266 int ret, newone, error, expireret = 0, retrycnt;
269 * For NFSv4, Open Ops are only done on Regular Files.
271 if (vnode_vtype(vp) != VREG)
275 mode |= NFSV4OPEN_ACCESSREAD;
277 mode |= NFSV4OPEN_ACCESSWRITE;
282 { char name[100]; int namel;
283 namel = (np->n_v4->n4_namelen < 100) ? np->n_v4->n4_namelen : 99;
284 bcopy(NFS4NODENAME(np->n_v4), name, namel);
286 printf("rpcopen p=0x%x name=%s",p->p_pid,name);
287 if (nfhp->nfh_len > 0) printf(" fh=0x%x\n",nfhp->nfh_fh[12]);
288 else printf(" fhl=0\n");
293 error = nfscl_open(vp, nfhp->nfh_fh, nfhp->nfh_len, mode, 1,
294 cred, p, NULL, &op, &newone, &ret, 1);
298 if (nmp->nm_clp != NULL)
299 clidrev = nmp->nm_clp->nfsc_clientidrev;
302 if (ret == NFSCLOPEN_DOOPEN) {
303 if (np->n_v4 != NULL) {
304 error = nfsrpc_openrpc(nmp, vp, np->n_v4->n4_data,
305 np->n_v4->n4_fhlen, np->n_fhp->nfh_fh,
306 np->n_fhp->nfh_len, mode, op,
307 NFS4NODENAME(np->n_v4), np->n_v4->n4_namelen, &dp,
308 0, 0x0, cred, p, 0, 0);
311 OSBitAndAtomic((int32_t)~NDELEGMOD, (UInt32 *)&np->n_flag);
314 np->n_flag &= ~NDELEGMOD;
316 * Invalidate the attribute cache, so that
317 * attributes that pre-date the issue of a
318 * delegation are not cached, since the
319 * cached attributes will remain valid while
320 * the delegation is held.
322 NFSINVALATTRCACHE(np);
325 (void) nfscl_deleg(nmp->nm_mountp,
326 op->nfso_own->nfsow_clp,
327 nfhp->nfh_fh, nfhp->nfh_len, cred, p, &dp);
332 newnfs_copyincred(cred, &op->nfso_cred);
333 } else if (ret == NFSCLOPEN_SETCRED)
335 * This is a new local open on a delegation. It needs
336 * to have credentials so that an open can be done
337 * against the server during recovery.
339 newnfs_copyincred(cred, &op->nfso_cred);
342 * nfso_opencnt is the count of how many VOP_OPEN()s have
343 * been done on this Open successfully and a VOP_CLOSE()
344 * is expected for each of these.
345 * If error is non-zero, don't increment it, since the Open
346 * hasn't succeeded yet.
350 nfscl_openrelease(nmp, op, error, newone);
351 if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
352 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
353 error == NFSERR_BADSESSION) {
354 (void) nfs_catnap(PZERO, error, "nfs_open");
355 } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID)
357 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
360 } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
361 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
362 error == NFSERR_BADSESSION ||
363 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
364 expireret == 0 && clidrev != 0 && retrycnt < 4));
365 if (error && retrycnt >= 4)
371 * the actual open rpc
374 nfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen,
375 u_int8_t *newfhp, int newfhlen, u_int32_t mode, struct nfsclopen *op,
376 u_int8_t *name, int namelen, struct nfscldeleg **dpp,
377 int reclaim, u_int32_t delegtype, struct ucred *cred, NFSPROC_T *p,
378 int syscred, int recursed)
381 struct nfsrv_descript nfsd, *nd = &nfsd;
382 struct nfscldeleg *dp, *ndp = NULL;
383 struct nfsvattr nfsva;
384 u_int32_t rflags, deleg;
385 nfsattrbit_t attrbits;
386 int error, ret, acesize, limitby;
387 struct nfsclsession *tsep;
391 nfscl_reqstart(nd, NFSPROC_OPEN, nmp, nfhp, fhlen, NULL, NULL);
392 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
393 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
394 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
395 *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
396 tsep = nfsmnt_mdssession(nmp);
397 *tl++ = tsep->nfsess_clientid.lval[0];
398 *tl = tsep->nfsess_clientid.lval[1];
399 (void) nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN);
400 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
401 *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE);
403 *tl = txdr_unsigned(NFSV4OPEN_CLAIMPREVIOUS);
404 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
405 *tl = txdr_unsigned(delegtype);
408 *tl = txdr_unsigned(NFSV4OPEN_CLAIMDELEGATECUR);
409 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
410 if (NFSHASNFSV4N(nmp))
413 *tl++ = dp->nfsdl_stateid.seqid;
414 *tl++ = dp->nfsdl_stateid.other[0];
415 *tl++ = dp->nfsdl_stateid.other[1];
416 *tl = dp->nfsdl_stateid.other[2];
418 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
420 (void) nfsm_strtom(nd, name, namelen);
422 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
423 *tl = txdr_unsigned(NFSV4OP_GETATTR);
424 NFSZERO_ATTRBIT(&attrbits);
425 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
426 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY);
427 (void) nfsrv_putattrbit(nd, &attrbits);
429 nd->nd_flag |= ND_USEGSSNAME;
430 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
431 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
434 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
435 if (!nd->nd_repstat) {
436 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
438 op->nfso_stateid.seqid = *tl++;
439 op->nfso_stateid.other[0] = *tl++;
440 op->nfso_stateid.other[1] = *tl++;
441 op->nfso_stateid.other[2] = *tl;
442 rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
443 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
446 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
447 deleg = fxdr_unsigned(u_int32_t, *tl);
448 if (deleg == NFSV4OPEN_DELEGATEREAD ||
449 deleg == NFSV4OPEN_DELEGATEWRITE) {
450 if (!(op->nfso_own->nfsow_clp->nfsc_flags &
451 NFSCLFLAGS_FIRSTDELEG))
452 op->nfso_own->nfsow_clp->nfsc_flags |=
453 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
454 MALLOC(ndp, struct nfscldeleg *,
455 sizeof (struct nfscldeleg) + newfhlen,
456 M_NFSCLDELEG, M_WAITOK);
457 LIST_INIT(&ndp->nfsdl_owner);
458 LIST_INIT(&ndp->nfsdl_lock);
459 ndp->nfsdl_clp = op->nfso_own->nfsow_clp;
460 ndp->nfsdl_fhlen = newfhlen;
461 NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen);
462 newnfs_copyincred(cred, &ndp->nfsdl_cred);
463 nfscl_lockinit(&ndp->nfsdl_rwlock);
464 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
466 ndp->nfsdl_stateid.seqid = *tl++;
467 ndp->nfsdl_stateid.other[0] = *tl++;
468 ndp->nfsdl_stateid.other[1] = *tl++;
469 ndp->nfsdl_stateid.other[2] = *tl++;
470 ret = fxdr_unsigned(int, *tl);
471 if (deleg == NFSV4OPEN_DELEGATEWRITE) {
472 ndp->nfsdl_flags = NFSCLDL_WRITE;
474 * Indicates how much the file can grow.
476 NFSM_DISSECT(tl, u_int32_t *,
478 limitby = fxdr_unsigned(int, *tl++);
480 case NFSV4OPEN_LIMITSIZE:
481 ndp->nfsdl_sizelimit = fxdr_hyper(tl);
483 case NFSV4OPEN_LIMITBLOCKS:
484 ndp->nfsdl_sizelimit =
485 fxdr_unsigned(u_int64_t, *tl++);
486 ndp->nfsdl_sizelimit *=
487 fxdr_unsigned(u_int64_t, *tl);
490 error = NFSERR_BADXDR;
494 ndp->nfsdl_flags = NFSCLDL_READ;
497 ndp->nfsdl_flags |= NFSCLDL_RECALL;
498 error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, &ret,
502 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
503 error = NFSERR_BADXDR;
506 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
507 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
508 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
509 NULL, NULL, NULL, p, cred);
513 ndp->nfsdl_change = nfsva.na_filerev;
514 ndp->nfsdl_modtime = nfsva.na_mtime;
515 ndp->nfsdl_flags |= NFSCLDL_MODTIMESET;
517 if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM)) {
519 ret = nfsrpc_openconfirm(vp, newfhp, newfhlen, op,
521 if (ret == NFSERR_DELAY)
522 (void) nfs_catnap(PZERO, ret, "nfs_open");
523 } while (ret == NFSERR_DELAY);
526 if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) ||
527 nfscl_assumeposixlocks)
528 op->nfso_posixlock = 1;
530 op->nfso_posixlock = 0;
533 * If the server is handing out delegations, but we didn't
534 * get one because an OpenConfirm was required, try the
535 * Open again, to get a delegation. This is a harmless no-op,
536 * from a server's point of view.
538 if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM) &&
539 (op->nfso_own->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG)
540 && !error && dp == NULL && ndp == NULL && !recursed) {
542 ret = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp,
543 newfhlen, mode, op, name, namelen, &ndp, 0, 0x0,
544 cred, p, syscred, 1);
545 if (ret == NFSERR_DELAY)
546 (void) nfs_catnap(PZERO, ret, "nfs_open2");
547 } while (ret == NFSERR_DELAY);
550 FREE((caddr_t)ndp, M_NFSCLDELEG);
551 if (ret == NFSERR_STALECLIENTID ||
552 ret == NFSERR_STALEDONTRECOVER ||
553 ret == NFSERR_BADSESSION)
558 if (nd->nd_repstat != 0 && error == 0)
559 error = nd->nd_repstat;
560 if (error == NFSERR_STALECLIENTID)
561 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
565 else if (ndp != NULL)
566 FREE((caddr_t)ndp, M_NFSCLDELEG);
567 mbuf_freem(nd->nd_mrep);
575 nfsrpc_opendowngrade(vnode_t vp, u_int32_t mode, struct nfsclopen *op,
576 struct ucred *cred, NFSPROC_T *p)
579 struct nfsrv_descript nfsd, *nd = &nfsd;
582 NFSCL_REQSTART(nd, NFSPROC_OPENDOWNGRADE, vp);
583 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
584 if (NFSHASNFSV4N(VFSTONFS(vnode_mount(vp))))
587 *tl++ = op->nfso_stateid.seqid;
588 *tl++ = op->nfso_stateid.other[0];
589 *tl++ = op->nfso_stateid.other[1];
590 *tl++ = op->nfso_stateid.other[2];
591 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
592 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
593 *tl = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
594 error = nfscl_request(nd, vp, p, cred, NULL);
597 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
598 if (!nd->nd_repstat) {
599 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
600 op->nfso_stateid.seqid = *tl++;
601 op->nfso_stateid.other[0] = *tl++;
602 op->nfso_stateid.other[1] = *tl++;
603 op->nfso_stateid.other[2] = *tl;
605 if (nd->nd_repstat && error == 0)
606 error = nd->nd_repstat;
607 if (error == NFSERR_STALESTATEID)
608 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
610 mbuf_freem(nd->nd_mrep);
615 * V4 Close operation.
618 nfsrpc_close(vnode_t vp, int doclose, NFSPROC_T *p)
620 struct nfsclclient *clp;
623 if (vnode_vtype(vp) != VREG)
626 error = nfscl_doclose(vp, &clp, p);
628 error = nfscl_getclose(vp, &clp);
632 nfscl_clientrelease(clp);
640 nfsrpc_doclose(struct nfsmount *nmp, struct nfsclopen *op, NFSPROC_T *p)
642 struct nfsrv_descript nfsd, *nd = &nfsd;
643 struct nfscllockowner *lp, *nlp;
644 struct nfscllock *lop, *nlop;
646 u_int64_t off = 0, len = 0;
647 u_int32_t type = NFSV4LOCKT_READ;
648 int error, do_unlock, trycnt;
650 tcred = newnfs_getcred();
651 newnfs_copycred(&op->nfso_cred, tcred);
653 * (Theoretically this could be done in the same
654 * compound as the close, but having multiple
655 * sequenced Ops in the same compound might be
656 * too scary for some servers.)
658 if (op->nfso_posixlock) {
661 type = NFSV4LOCKT_READ;
665 * Since this function is only called from VOP_INACTIVE(), no
666 * other thread will be manipulating this Open. As such, the
667 * lock lists are not being changed by other threads, so it should
668 * be safe to do this without locking.
670 LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) {
672 LIST_FOREACH_SAFE(lop, &lp->nfsl_lock, nfslo_list, nlop) {
673 if (op->nfso_posixlock == 0) {
674 off = lop->nfslo_first;
675 len = lop->nfslo_end - lop->nfslo_first;
676 if (lop->nfslo_type == F_WRLCK)
677 type = NFSV4LOCKT_WRITE;
679 type = NFSV4LOCKT_READ;
684 error = nfsrpc_locku(nd, nmp, lp, off,
685 len, type, tcred, p, 0);
686 if ((nd->nd_repstat == NFSERR_GRACE ||
687 nd->nd_repstat == NFSERR_DELAY) &&
689 (void) nfs_catnap(PZERO,
692 } while ((nd->nd_repstat == NFSERR_GRACE ||
693 nd->nd_repstat == NFSERR_DELAY) &&
694 error == 0 && trycnt++ < 5);
695 if (op->nfso_posixlock)
698 nfscl_freelock(lop, 0);
701 * Do a ReleaseLockOwner.
702 * The lock owner name nfsl_owner may be used by other opens for
703 * other files but the lock_owner4 name that nfsrpc_rellockown()
704 * puts on the wire has the file handle for this file appended
705 * to it, so it can be done now.
707 (void)nfsrpc_rellockown(nmp, lp, lp->nfsl_open->nfso_fh,
708 lp->nfsl_open->nfso_fhlen, tcred, p);
712 * There could be other Opens for different files on the same
713 * OpenOwner, so locking is required.
716 nfscl_lockexcl(&op->nfso_own->nfsow_rwlock, NFSCLSTATEMUTEXPTR);
719 error = nfscl_tryclose(op, tcred, nmp, p);
720 if (error == NFSERR_GRACE)
721 (void) nfs_catnap(PZERO, error, "nfs_close");
722 } while (error == NFSERR_GRACE);
724 nfscl_lockunlock(&op->nfso_own->nfsow_rwlock);
726 LIST_FOREACH_SAFE(lp, &op->nfso_lock, nfsl_list, nlp)
727 nfscl_freelockowner(lp, 0);
728 nfscl_freeopen(op, 0);
734 * The actual Close RPC.
737 nfsrpc_closerpc(struct nfsrv_descript *nd, struct nfsmount *nmp,
738 struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p,
744 nfscl_reqstart(nd, NFSPROC_CLOSE, nmp, op->nfso_fh,
745 op->nfso_fhlen, NULL, NULL);
746 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
747 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
748 if (NFSHASNFSV4N(nmp))
751 *tl++ = op->nfso_stateid.seqid;
752 *tl++ = op->nfso_stateid.other[0];
753 *tl++ = op->nfso_stateid.other[1];
754 *tl = op->nfso_stateid.other[2];
756 nd->nd_flag |= ND_USEGSSNAME;
757 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
758 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
761 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
762 if (nd->nd_repstat == 0)
763 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
764 error = nd->nd_repstat;
765 if (error == NFSERR_STALESTATEID)
766 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
768 mbuf_freem(nd->nd_mrep);
773 * V4 Open Confirm RPC.
776 nfsrpc_openconfirm(vnode_t vp, u_int8_t *nfhp, int fhlen,
777 struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p)
780 struct nfsrv_descript nfsd, *nd = &nfsd;
781 struct nfsmount *nmp;
784 nmp = VFSTONFS(vnode_mount(vp));
785 if (NFSHASNFSV4N(nmp))
786 return (0); /* No confirmation for NFSv4.1. */
787 nfscl_reqstart(nd, NFSPROC_OPENCONFIRM, nmp, nfhp, fhlen, NULL, NULL);
788 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
789 *tl++ = op->nfso_stateid.seqid;
790 *tl++ = op->nfso_stateid.other[0];
791 *tl++ = op->nfso_stateid.other[1];
792 *tl++ = op->nfso_stateid.other[2];
793 *tl = txdr_unsigned(op->nfso_own->nfsow_seqid);
794 error = nfscl_request(nd, vp, p, cred, NULL);
797 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
798 if (!nd->nd_repstat) {
799 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
800 op->nfso_stateid.seqid = *tl++;
801 op->nfso_stateid.other[0] = *tl++;
802 op->nfso_stateid.other[1] = *tl++;
803 op->nfso_stateid.other[2] = *tl;
805 error = nd->nd_repstat;
806 if (error == NFSERR_STALESTATEID)
807 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
809 mbuf_freem(nd->nd_mrep);
814 * Do the setclientid and setclientid confirm RPCs. Called from nfs_statfs()
815 * when a mount has just occurred and when the server replies NFSERR_EXPIRED.
818 nfsrpc_setclient(struct nfsmount *nmp, struct nfsclclient *clp, int reclaim,
819 struct ucred *cred, NFSPROC_T *p)
822 struct nfsrv_descript nfsd;
823 struct nfsrv_descript *nd = &nfsd;
824 nfsattrbit_t attrbits;
825 u_int8_t *cp = NULL, *cp2, addr[INET6_ADDRSTRLEN + 9];
827 int error, isinet6 = 0, callblen;
830 static u_int32_t rev = 0;
832 struct nfsclsession *tsep;
834 if (nfsboottime.tv_sec == 0)
835 NFSSETBOOTTIME(nfsboottime);
836 clp->nfsc_rev = rev++;
837 if (NFSHASNFSV4N(nmp)) {
839 * Either there was no previous session or the
840 * previous session has failed, so...
841 * do an ExchangeID followed by the CreateSession.
843 error = nfsrpc_exchangeid(nmp, clp, &nmp->nm_sockreq,
844 NFSV4EXCH_USEPNFSMDS | NFSV4EXCH_USENONPNFS, &dsp, cred, p);
845 NFSCL_DEBUG(1, "aft exch=%d\n", error);
847 error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess,
849 dsp->nfsclds_sess.nfsess_sequenceid, 1, cred, p);
853 * The old sessions cannot be safely free'd
854 * here, since they may still be used by
858 if (TAILQ_FIRST(&nmp->nm_sess) != NULL)
859 tsep = NFSMNT_MDSSESSION(nmp);
860 TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp,
863 * Wake up RPCs waiting for a slot on the
864 * old session. These will then fail with
865 * NFSERR_BADSESSION and be retried with the
866 * new session by nfsv4_setsequence().
867 * Also wakeup() processes waiting for the
871 wakeup(&tsep->nfsess_slots);
872 wakeup(&nmp->nm_sess);
875 nfscl_freenfsclds(dsp);
876 NFSCL_DEBUG(1, "aft createsess=%d\n", error);
877 if (error == 0 && reclaim == 0) {
878 error = nfsrpc_reclaimcomplete(nmp, cred, p);
879 NFSCL_DEBUG(1, "aft reclaimcomp=%d\n", error);
880 if (error == NFSERR_COMPLETEALREADY ||
881 error == NFSERR_NOTSUPP)
882 /* Ignore this error. */
889 * Allocate a single session structure for NFSv4.0, because some of
890 * the fields are used by NFSv4.0 although it doesn't do a session.
892 dsp = malloc(sizeof(struct nfsclds), M_NFSCLDS, M_WAITOK | M_ZERO);
893 mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF);
894 mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", NULL, MTX_DEF);
896 TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp, nfsclds_list);
897 tsep = NFSMNT_MDSSESSION(nmp);
900 nfscl_reqstart(nd, NFSPROC_SETCLIENTID, nmp, NULL, 0, NULL, NULL);
901 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
902 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
903 *tl = txdr_unsigned(clp->nfsc_rev);
904 (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen);
907 * set up the callback address
909 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
910 *tl = txdr_unsigned(NFS_CALLBCKPROG);
911 callblen = strlen(nfsv4_callbackaddr);
913 cp = nfscl_getmyip(nmp, &isinet6);
914 if (nfscl_enablecallb && nfs_numnfscbd > 0 &&
915 (callblen > 0 || cp != NULL)) {
916 port = htons(nfsv4_cbport);
917 cp2 = (u_int8_t *)&port;
920 strchr(nfsv4_callbackaddr, ':')) || isinet6) {
921 char ip6buf[INET6_ADDRSTRLEN], *ip6add;
923 (void) nfsm_strtom(nd, "tcp6", 4);
925 ip6_sprintf(ip6buf, (struct in6_addr *)cp);
928 ip6add = nfsv4_callbackaddr;
930 snprintf(addr, INET6_ADDRSTRLEN + 9, "%s.%d.%d",
931 ip6add, cp2[0], cp2[1]);
935 (void) nfsm_strtom(nd, "tcp", 3);
937 snprintf(addr, INET6_ADDRSTRLEN + 9,
938 "%d.%d.%d.%d.%d.%d", cp[0], cp[1],
939 cp[2], cp[3], cp2[0], cp2[1]);
941 snprintf(addr, INET6_ADDRSTRLEN + 9,
942 "%s.%d.%d", nfsv4_callbackaddr,
945 (void) nfsm_strtom(nd, addr, strlen(addr));
947 (void) nfsm_strtom(nd, "tcp", 3);
948 (void) nfsm_strtom(nd, "0.0.0.0.0.0", 11);
950 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
951 *tl = txdr_unsigned(clp->nfsc_cbident);
952 nd->nd_flag |= ND_USEGSSNAME;
953 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
954 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
957 if (nd->nd_repstat == 0) {
958 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
959 tsep->nfsess_clientid.lval[0] = *tl++;
960 tsep->nfsess_clientid.lval[1] = *tl++;
961 confirm.lval[0] = *tl++;
962 confirm.lval[1] = *tl;
963 mbuf_freem(nd->nd_mrep);
969 nfscl_reqstart(nd, NFSPROC_SETCLIENTIDCFRM, nmp, NULL, 0, NULL,
971 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
972 *tl++ = tsep->nfsess_clientid.lval[0];
973 *tl++ = tsep->nfsess_clientid.lval[1];
974 *tl++ = confirm.lval[0];
975 *tl = confirm.lval[1];
976 nd->nd_flag |= ND_USEGSSNAME;
977 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p,
978 cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
981 mbuf_freem(nd->nd_mrep);
983 if (nd->nd_repstat == 0) {
984 nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, nmp->nm_fh,
985 nmp->nm_fhsize, NULL, NULL);
986 NFSZERO_ATTRBIT(&attrbits);
987 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME);
988 (void) nfsrv_putattrbit(nd, &attrbits);
989 nd->nd_flag |= ND_USEGSSNAME;
990 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p,
991 cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
994 if (nd->nd_repstat == 0) {
995 error = nfsv4_loadattr(nd, NULL, NULL, NULL, NULL, 0, NULL,
996 NULL, NULL, NULL, NULL, 0, NULL, &lease, NULL, p, cred);
999 clp->nfsc_renew = NFSCL_RENEW(lease);
1000 clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew;
1001 clp->nfsc_clientidrev++;
1002 if (clp->nfsc_clientidrev == 0)
1003 clp->nfsc_clientidrev++;
1007 error = nd->nd_repstat;
1009 mbuf_freem(nd->nd_mrep);
1017 nfsrpc_getattr(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
1018 struct nfsvattr *nap, void *stuff)
1020 struct nfsrv_descript nfsd, *nd = &nfsd;
1022 nfsattrbit_t attrbits;
1024 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
1025 if (nd->nd_flag & ND_NFSV4) {
1026 NFSGETATTR_ATTRBIT(&attrbits);
1027 (void) nfsrv_putattrbit(nd, &attrbits);
1029 error = nfscl_request(nd, vp, p, cred, stuff);
1032 if (!nd->nd_repstat)
1033 error = nfsm_loadattr(nd, nap);
1035 error = nd->nd_repstat;
1036 mbuf_freem(nd->nd_mrep);
1041 * nfs getattr call with non-vnode arguemnts.
1044 nfsrpc_getattrnovp(struct nfsmount *nmp, u_int8_t *fhp, int fhlen, int syscred,
1045 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, u_int64_t *xidp,
1048 struct nfsrv_descript nfsd, *nd = &nfsd;
1049 int error, vers = NFS_VER2;
1050 nfsattrbit_t attrbits;
1052 nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, fhp, fhlen, NULL, NULL);
1053 if (nd->nd_flag & ND_NFSV4) {
1055 NFSGETATTR_ATTRBIT(&attrbits);
1056 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME);
1057 (void) nfsrv_putattrbit(nd, &attrbits);
1058 } else if (nd->nd_flag & ND_NFSV3) {
1062 nd->nd_flag |= ND_USEGSSNAME;
1063 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
1064 NFS_PROG, vers, NULL, 1, xidp, NULL);
1067 if (nd->nd_repstat == 0) {
1068 if ((nd->nd_flag & ND_NFSV4) != 0)
1069 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
1070 NULL, NULL, NULL, NULL, NULL, 0, NULL, leasep, NULL,
1073 error = nfsm_loadattr(nd, nap);
1075 error = nd->nd_repstat;
1076 mbuf_freem(nd->nd_mrep);
1081 * Do an nfs setattr operation.
1084 nfsrpc_setattr(vnode_t vp, struct vattr *vap, NFSACL_T *aclp,
1085 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *rnap, int *attrflagp,
1088 int error, expireret = 0, openerr, retrycnt;
1089 u_int32_t clidrev = 0, mode;
1090 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1092 nfsv4stateid_t stateid;
1095 if (nmp->nm_clp != NULL)
1096 clidrev = nmp->nm_clp->nfsc_clientidrev;
1097 if (vap != NULL && NFSATTRISSET(u_quad_t, vap, va_size))
1098 mode = NFSV4OPEN_ACCESSWRITE;
1100 mode = NFSV4OPEN_ACCESSREAD;
1105 if (NFSHASNFSV4(nmp)) {
1106 nfhp = VTONFS(vp)->n_fhp;
1107 error = nfscl_getstateid(vp, nfhp->nfh_fh,
1108 nfhp->nfh_len, mode, 0, cred, p, &stateid, &lckp);
1109 if (error && vnode_vtype(vp) == VREG &&
1110 (mode == NFSV4OPEN_ACCESSWRITE ||
1111 nfstest_openallsetattr)) {
1113 * No Open stateid, so try and open the file
1116 if (mode == NFSV4OPEN_ACCESSWRITE)
1117 openerr = nfsrpc_open(vp, FWRITE, cred,
1120 openerr = nfsrpc_open(vp, FREAD, cred,
1123 (void) nfscl_getstateid(vp,
1124 nfhp->nfh_fh, nfhp->nfh_len,
1125 mode, 0, cred, p, &stateid, &lckp);
1129 error = nfsrpc_setattrrpc(vp, vap, &stateid, cred, p,
1130 rnap, attrflagp, stuff);
1132 error = nfsrpc_setaclrpc(vp, cred, p, aclp, &stateid,
1134 if (error == NFSERR_STALESTATEID)
1135 nfscl_initiate_recovery(nmp->nm_clp);
1137 nfscl_lockderef(lckp);
1139 (void) nfsrpc_close(vp, 0, p);
1140 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1141 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1142 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
1143 (void) nfs_catnap(PZERO, error, "nfs_setattr");
1144 } else if ((error == NFSERR_EXPIRED ||
1145 error == NFSERR_BADSTATEID) && clidrev != 0) {
1146 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1149 } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1150 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1151 error == NFSERR_BADSESSION ||
1152 (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
1153 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1154 expireret == 0 && clidrev != 0 && retrycnt < 4));
1155 if (error && retrycnt >= 4)
1161 nfsrpc_setattrrpc(vnode_t vp, struct vattr *vap,
1162 nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p,
1163 struct nfsvattr *rnap, int *attrflagp, void *stuff)
1166 struct nfsrv_descript nfsd, *nd = &nfsd;
1168 nfsattrbit_t attrbits;
1171 NFSCL_REQSTART(nd, NFSPROC_SETATTR, vp);
1172 if (nd->nd_flag & ND_NFSV4)
1173 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
1174 vap->va_type = vnode_vtype(vp);
1175 nfscl_fillsattr(nd, vap, vp, NFSSATTR_FULL, 0);
1176 if (nd->nd_flag & ND_NFSV3) {
1177 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1179 } else if (nd->nd_flag & ND_NFSV4) {
1180 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1181 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1182 NFSGETATTR_ATTRBIT(&attrbits);
1183 (void) nfsrv_putattrbit(nd, &attrbits);
1185 error = nfscl_request(nd, vp, p, cred, stuff);
1188 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
1189 error = nfscl_wcc_data(nd, vp, rnap, attrflagp, NULL, stuff);
1190 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 && !error)
1191 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1192 if (!(nd->nd_flag & ND_NFSV3) && !nd->nd_repstat && !error)
1193 error = nfscl_postop_attr(nd, rnap, attrflagp, stuff);
1194 mbuf_freem(nd->nd_mrep);
1195 if (nd->nd_repstat && !error)
1196 error = nd->nd_repstat;
1204 nfsrpc_lookup(vnode_t dvp, char *name, int len, struct ucred *cred,
1205 NFSPROC_T *p, struct nfsvattr *dnap, struct nfsvattr *nap,
1206 struct nfsfh **nfhpp, int *attrflagp, int *dattrflagp, void *stuff)
1209 struct nfsrv_descript nfsd, *nd = &nfsd;
1210 struct nfsmount *nmp;
1213 nfsattrbit_t attrbits;
1214 int error = 0, lookupp = 0;
1218 if (vnode_vtype(dvp) != VDIR)
1220 nmp = VFSTONFS(vnode_mount(dvp));
1221 if (len > NFS_MAXNAMLEN)
1222 return (ENAMETOOLONG);
1223 if (NFSHASNFSV4(nmp) && len == 1 &&
1226 * Just return the current dir's fh.
1229 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) +
1230 np->n_fhp->nfh_len, M_NFSFH, M_WAITOK);
1231 nfhp->nfh_len = np->n_fhp->nfh_len;
1232 NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len);
1236 if (NFSHASNFSV4(nmp) && len == 2 &&
1237 name[0] == '.' && name[1] == '.') {
1239 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, dvp);
1241 NFSCL_REQSTART(nd, NFSPROC_LOOKUP, dvp);
1242 (void) nfsm_strtom(nd, name, len);
1244 if (nd->nd_flag & ND_NFSV4) {
1245 NFSGETATTR_ATTRBIT(&attrbits);
1246 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1247 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
1248 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1249 (void) nfsrv_putattrbit(nd, &attrbits);
1251 error = nfscl_request(nd, dvp, p, cred, stuff);
1254 if (nd->nd_repstat) {
1256 * When an NFSv4 Lookupp returns ENOENT, it means that
1257 * the lookup is at the root of an fs, so return this dir.
1259 if (nd->nd_repstat == NFSERR_NOENT && lookupp) {
1261 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) +
1262 np->n_fhp->nfh_len, M_NFSFH, M_WAITOK);
1263 nfhp->nfh_len = np->n_fhp->nfh_len;
1264 NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len);
1266 mbuf_freem(nd->nd_mrep);
1269 if (nd->nd_flag & ND_NFSV3)
1270 error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff);
1271 else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
1273 /* Load the directory attributes. */
1274 error = nfsm_loadattr(nd, dnap);
1280 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
1281 /* Load the directory attributes. */
1282 error = nfsm_loadattr(nd, dnap);
1286 /* Skip over the Lookup and GetFH operation status values. */
1287 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1289 error = nfsm_getfh(nd, nfhpp);
1293 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
1294 if ((nd->nd_flag & ND_NFSV3) && !error)
1295 error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff);
1297 mbuf_freem(nd->nd_mrep);
1298 if (!error && nd->nd_repstat)
1299 error = nd->nd_repstat;
1304 * Do a readlink rpc.
1307 nfsrpc_readlink(vnode_t vp, struct uio *uiop, struct ucred *cred,
1308 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
1311 struct nfsrv_descript nfsd, *nd = &nfsd;
1312 struct nfsnode *np = VTONFS(vp);
1313 nfsattrbit_t attrbits;
1314 int error, len, cangetattr = 1;
1317 NFSCL_REQSTART(nd, NFSPROC_READLINK, vp);
1318 if (nd->nd_flag & ND_NFSV4) {
1320 * And do a Getattr op.
1322 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1323 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1324 NFSGETATTR_ATTRBIT(&attrbits);
1325 (void) nfsrv_putattrbit(nd, &attrbits);
1327 error = nfscl_request(nd, vp, p, cred, stuff);
1330 if (nd->nd_flag & ND_NFSV3)
1331 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
1332 if (!nd->nd_repstat && !error) {
1333 NFSM_STRSIZ(len, NFS_MAXPATHLEN);
1335 * This seems weird to me, but must have been added to
1336 * FreeBSD for some reason. The only thing I can think of
1337 * is that there was/is some server that replies with
1338 * more link data than it should?
1340 if (len == NFS_MAXPATHLEN) {
1342 if (np->n_size > 0 && np->n_size < NFS_MAXPATHLEN) {
1348 error = nfsm_mbufuio(nd, uiop, len);
1349 if ((nd->nd_flag & ND_NFSV4) && !error && cangetattr)
1350 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
1352 if (nd->nd_repstat && !error)
1353 error = nd->nd_repstat;
1355 mbuf_freem(nd->nd_mrep);
1363 nfsrpc_read(vnode_t vp, struct uio *uiop, struct ucred *cred,
1364 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
1366 int error, expireret = 0, retrycnt;
1367 u_int32_t clidrev = 0;
1368 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1369 struct nfsnode *np = VTONFS(vp);
1370 struct ucred *newcred;
1371 struct nfsfh *nfhp = NULL;
1372 nfsv4stateid_t stateid;
1375 if (nmp->nm_clp != NULL)
1376 clidrev = nmp->nm_clp->nfsc_clientidrev;
1378 if (NFSHASNFSV4(nmp)) {
1380 newcred = NFSNEWCRED(cred);
1385 if (NFSHASNFSV4(nmp))
1386 (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
1387 NFSV4OPEN_ACCESSREAD, 0, newcred, p, &stateid,
1389 error = nfsrpc_readrpc(vp, uiop, newcred, &stateid, p, nap,
1391 if (error == NFSERR_STALESTATEID)
1392 nfscl_initiate_recovery(nmp->nm_clp);
1394 nfscl_lockderef(lckp);
1395 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1396 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1397 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
1398 (void) nfs_catnap(PZERO, error, "nfs_read");
1399 } else if ((error == NFSERR_EXPIRED ||
1400 error == NFSERR_BADSTATEID) && clidrev != 0) {
1401 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1404 } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1405 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1406 error == NFSERR_BADSESSION ||
1407 (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
1408 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1409 expireret == 0 && clidrev != 0 && retrycnt < 4));
1410 if (error && retrycnt >= 4)
1412 if (NFSHASNFSV4(nmp))
1413 NFSFREECRED(newcred);
1418 * The actual read RPC.
1421 nfsrpc_readrpc(vnode_t vp, struct uio *uiop, struct ucred *cred,
1422 nfsv4stateid_t *stateidp, NFSPROC_T *p, struct nfsvattr *nap,
1423 int *attrflagp, void *stuff)
1426 int error = 0, len, retlen, tsiz, eof = 0;
1427 struct nfsrv_descript nfsd;
1428 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1429 struct nfsrv_descript *nd = &nfsd;
1434 tsiz = uio_uio_resid(uiop);
1435 tmp_off = uiop->uio_offset + tsiz;
1437 if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) {
1441 rsize = nmp->nm_rsize;
1446 len = (tsiz > rsize) ? rsize : tsiz;
1447 NFSCL_REQSTART(nd, NFSPROC_READ, vp);
1448 if (nd->nd_flag & ND_NFSV4)
1449 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
1450 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED * 3);
1451 if (nd->nd_flag & ND_NFSV2) {
1452 *tl++ = txdr_unsigned(uiop->uio_offset);
1453 *tl++ = txdr_unsigned(len);
1456 txdr_hyper(uiop->uio_offset, tl);
1457 *(tl + 2) = txdr_unsigned(len);
1460 * Since I can't do a Getattr for NFSv4 for Write, there
1461 * doesn't seem any point in doing one here, either.
1462 * (See the comment in nfsrpc_writerpc() for more info.)
1464 error = nfscl_request(nd, vp, p, cred, stuff);
1467 if (nd->nd_flag & ND_NFSV3) {
1468 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
1469 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
1470 error = nfsm_loadattr(nd, nap);
1474 if (nd->nd_repstat || error) {
1476 error = nd->nd_repstat;
1479 if (nd->nd_flag & ND_NFSV3) {
1480 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1481 eof = fxdr_unsigned(int, *(tl + 1));
1482 } else if (nd->nd_flag & ND_NFSV4) {
1483 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1484 eof = fxdr_unsigned(int, *tl);
1486 NFSM_STRSIZ(retlen, len);
1487 error = nfsm_mbufuio(nd, uiop, retlen);
1490 mbuf_freem(nd->nd_mrep);
1493 if (!(nd->nd_flag & ND_NFSV2)) {
1494 if (eof || retlen == 0)
1496 } else if (retlen < len)
1501 if (nd->nd_mrep != NULL)
1502 mbuf_freem(nd->nd_mrep);
1507 * nfs write operation
1508 * When called_from_strategy != 0, it should return EIO for an error that
1509 * indicates recovery is in progress, so that the buffer will be left
1510 * dirty and be written back to the server later. If it loops around,
1511 * the recovery thread could get stuck waiting for the buffer and recovery
1512 * will then deadlock.
1515 nfsrpc_write(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
1516 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
1517 void *stuff, int called_from_strategy)
1519 int error, expireret = 0, retrycnt, nostateid;
1520 u_int32_t clidrev = 0;
1521 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1522 struct nfsnode *np = VTONFS(vp);
1523 struct ucred *newcred;
1524 struct nfsfh *nfhp = NULL;
1525 nfsv4stateid_t stateid;
1529 if (nmp->nm_clp != NULL)
1530 clidrev = nmp->nm_clp->nfsc_clientidrev;
1532 if (NFSHASNFSV4(nmp)) {
1533 newcred = NFSNEWCRED(cred);
1540 if (NFSHASNFSV4(nmp)) {
1541 (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
1542 NFSV4OPEN_ACCESSWRITE, 0, newcred, p, &stateid,
1544 if (stateid.other[0] == 0 && stateid.other[1] == 0 &&
1545 stateid.other[2] == 0) {
1547 NFSCL_DEBUG(1, "stateid0 in write\n");
1552 * If there is no stateid for NFSv4, it means this is an
1553 * extraneous write after close. Basically a poorly
1554 * implemented buffer cache. Just don't do the write.
1559 error = nfsrpc_writerpc(vp, uiop, iomode, must_commit,
1560 newcred, &stateid, p, nap, attrflagp, stuff);
1561 if (error == NFSERR_STALESTATEID)
1562 nfscl_initiate_recovery(nmp->nm_clp);
1564 nfscl_lockderef(lckp);
1565 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1566 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1567 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
1568 (void) nfs_catnap(PZERO, error, "nfs_write");
1569 } else if ((error == NFSERR_EXPIRED ||
1570 error == NFSERR_BADSTATEID) && clidrev != 0) {
1571 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1574 } while (error == NFSERR_GRACE || error == NFSERR_DELAY ||
1575 ((error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION ||
1576 error == NFSERR_STALEDONTRECOVER) && called_from_strategy == 0) ||
1577 (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
1578 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1579 expireret == 0 && clidrev != 0 && retrycnt < 4));
1580 if (error != 0 && (retrycnt >= 4 ||
1581 ((error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION ||
1582 error == NFSERR_STALEDONTRECOVER) && called_from_strategy != 0)))
1584 if (NFSHASNFSV4(nmp))
1585 NFSFREECRED(newcred);
1590 * The actual write RPC.
1593 nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode,
1594 int *must_commit, struct ucred *cred, nfsv4stateid_t *stateidp,
1595 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
1598 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1599 struct nfsnode *np = VTONFS(vp);
1600 int error = 0, len, tsiz, rlen, commit, committed = NFSWRITE_FILESYNC;
1601 int wccflag = 0, wsize;
1603 struct nfsrv_descript nfsd;
1604 struct nfsrv_descript *nd = &nfsd;
1605 nfsattrbit_t attrbits;
1608 KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1"));
1610 tsiz = uio_uio_resid(uiop);
1611 tmp_off = uiop->uio_offset + tsiz;
1613 if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) {
1617 wsize = nmp->nm_wsize;
1619 nd->nd_mrep = NULL; /* NFSv2 sometimes does a write with */
1620 nd->nd_repstat = 0; /* uio_resid == 0, so the while is not done */
1623 len = (tsiz > wsize) ? wsize : tsiz;
1624 NFSCL_REQSTART(nd, NFSPROC_WRITE, vp);
1625 if (nd->nd_flag & ND_NFSV4) {
1626 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
1627 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+2*NFSX_UNSIGNED);
1628 txdr_hyper(uiop->uio_offset, tl);
1630 *tl++ = txdr_unsigned(*iomode);
1631 *tl = txdr_unsigned(len);
1632 } else if (nd->nd_flag & ND_NFSV3) {
1633 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+3*NFSX_UNSIGNED);
1634 txdr_hyper(uiop->uio_offset, tl);
1636 *tl++ = txdr_unsigned(len);
1637 *tl++ = txdr_unsigned(*iomode);
1638 *tl = txdr_unsigned(len);
1642 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1644 * Not sure why someone changed this, since the
1645 * RFC clearly states that "beginoffset" and
1646 * "totalcount" are ignored, but it wouldn't
1647 * surprise me if there's a busted server out there.
1649 /* Set both "begin" and "current" to non-garbage. */
1650 x = txdr_unsigned((u_int32_t)uiop->uio_offset);
1651 *tl++ = x; /* "begin offset" */
1652 *tl++ = x; /* "current offset" */
1653 x = txdr_unsigned(len);
1654 *tl++ = x; /* total to this offset */
1655 *tl = x; /* size of this write */
1658 nfsm_uiombuf(nd, uiop, len);
1660 * Although it is tempting to do a normal Getattr Op in the
1661 * NFSv4 compound, the result can be a nearly hung client
1662 * system if the Getattr asks for Owner and/or OwnerGroup.
1663 * It occurs when the client can't map either the Owner or
1664 * Owner_group name in the Getattr reply to a uid/gid. When
1665 * there is a cache miss, the kernel does an upcall to the
1666 * nfsuserd. Then, it can try and read the local /etc/passwd
1667 * or /etc/group file. It can then block in getnewbuf(),
1668 * waiting for dirty writes to be pushed to the NFS server.
1669 * The only reason this doesn't result in a complete
1670 * deadlock, is that the upcall times out and allows
1671 * the write to complete. However, progress is so slow
1672 * that it might just as well be deadlocked.
1673 * As such, we get the rest of the attributes, but not
1674 * Owner or Owner_group.
1675 * nb: nfscl_loadattrcache() needs to be told that these
1676 * partial attributes from a write rpc are being
1677 * passed in, via a argument flag.
1679 if (nd->nd_flag & ND_NFSV4) {
1680 NFSWRITEGETATTR_ATTRBIT(&attrbits);
1681 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1682 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1683 (void) nfsrv_putattrbit(nd, &attrbits);
1685 error = nfscl_request(nd, vp, p, cred, stuff);
1688 if (nd->nd_repstat) {
1690 * In case the rpc gets retried, roll
1691 * the uio fileds changed by nfsm_uiombuf()
1694 uiop->uio_offset -= len;
1695 uio_uio_resid_add(uiop, len);
1696 uio_iov_base_add(uiop, -len);
1697 uio_iov_len_add(uiop, len);
1699 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1700 error = nfscl_wcc_data(nd, vp, nap, attrflagp,
1705 if (!nd->nd_repstat) {
1706 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1707 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED
1709 rlen = fxdr_unsigned(int, *tl++);
1713 } else if (rlen < len) {
1714 backup = len - rlen;
1715 uio_iov_base_add(uiop, -(backup));
1716 uio_iov_len_add(uiop, backup);
1717 uiop->uio_offset -= backup;
1718 uio_uio_resid_add(uiop, backup);
1721 commit = fxdr_unsigned(int, *tl++);
1724 * Return the lowest committment level
1725 * obtained by any of the RPCs.
1727 if (committed == NFSWRITE_FILESYNC)
1729 else if (committed == NFSWRITE_DATASYNC &&
1730 commit == NFSWRITE_UNSTABLE)
1733 if (!NFSHASWRITEVERF(nmp)) {
1734 NFSBCOPY((caddr_t)tl,
1735 (caddr_t)&nmp->nm_verf[0],
1737 NFSSETWRITEVERF(nmp);
1738 } else if (NFSBCMP(tl, nmp->nm_verf,
1741 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
1745 if (nd->nd_flag & ND_NFSV4)
1746 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1747 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV4)) {
1748 error = nfsm_loadattr(nd, nap);
1750 *attrflagp = NFS_LATTR_NOSHRINK;
1753 error = nd->nd_repstat;
1757 NFSWRITERPC_SETTIME(wccflag, np, nap, (nd->nd_flag & ND_NFSV4));
1758 mbuf_freem(nd->nd_mrep);
1763 if (nd->nd_mrep != NULL)
1764 mbuf_freem(nd->nd_mrep);
1765 *iomode = committed;
1766 if (nd->nd_repstat && !error)
1767 error = nd->nd_repstat;
1773 * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the
1774 * mode set to specify the file type and the size field for rdev.
1777 nfsrpc_mknod(vnode_t dvp, char *name, int namelen, struct vattr *vap,
1778 u_int32_t rdev, enum vtype vtyp, struct ucred *cred, NFSPROC_T *p,
1779 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
1780 int *attrflagp, int *dattrflagp, void *dstuff)
1784 struct nfsrv_descript nfsd, *nd = &nfsd;
1785 nfsattrbit_t attrbits;
1790 if (namelen > NFS_MAXNAMLEN)
1791 return (ENAMETOOLONG);
1792 NFSCL_REQSTART(nd, NFSPROC_MKNOD, dvp);
1793 if (nd->nd_flag & ND_NFSV4) {
1794 if (vtyp == VBLK || vtyp == VCHR) {
1795 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1796 *tl++ = vtonfsv34_type(vtyp);
1797 *tl++ = txdr_unsigned(NFSMAJOR(rdev));
1798 *tl = txdr_unsigned(NFSMINOR(rdev));
1800 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1801 *tl = vtonfsv34_type(vtyp);
1804 (void) nfsm_strtom(nd, name, namelen);
1805 if (nd->nd_flag & ND_NFSV3) {
1806 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1807 *tl = vtonfsv34_type(vtyp);
1809 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
1810 nfscl_fillsattr(nd, vap, dvp, 0, 0);
1811 if ((nd->nd_flag & ND_NFSV3) &&
1812 (vtyp == VCHR || vtyp == VBLK)) {
1813 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1814 *tl++ = txdr_unsigned(NFSMAJOR(rdev));
1815 *tl = txdr_unsigned(NFSMINOR(rdev));
1817 if (nd->nd_flag & ND_NFSV4) {
1818 NFSGETATTR_ATTRBIT(&attrbits);
1819 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1820 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
1821 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1822 (void) nfsrv_putattrbit(nd, &attrbits);
1824 if (nd->nd_flag & ND_NFSV2)
1825 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZERDEV, rdev);
1826 error = nfscl_request(nd, dvp, p, cred, dstuff);
1829 if (nd->nd_flag & ND_NFSV4)
1830 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
1831 if (!nd->nd_repstat) {
1832 if (nd->nd_flag & ND_NFSV4) {
1833 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1834 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1838 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
1842 if (nd->nd_flag & ND_NFSV3)
1843 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
1844 if (!error && nd->nd_repstat)
1845 error = nd->nd_repstat;
1847 mbuf_freem(nd->nd_mrep);
1852 * nfs file create call
1853 * Mostly just call the approriate routine. (I separated out v4, so that
1854 * error recovery wouldn't be as difficult.)
1857 nfsrpc_create(vnode_t dvp, char *name, int namelen, struct vattr *vap,
1858 nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p,
1859 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
1860 int *attrflagp, int *dattrflagp, void *dstuff)
1862 int error = 0, newone, expireret = 0, retrycnt, unlocked;
1863 struct nfsclowner *owp;
1864 struct nfscldeleg *dp;
1865 struct nfsmount *nmp = VFSTONFS(vnode_mount(dvp));
1868 if (NFSHASNFSV4(nmp)) {
1872 error = nfscl_open(dvp, NULL, 0, (NFSV4OPEN_ACCESSWRITE |
1873 NFSV4OPEN_ACCESSREAD), 0, cred, p, &owp, NULL, &newone,
1877 if (nmp->nm_clp != NULL)
1878 clidrev = nmp->nm_clp->nfsc_clientidrev;
1881 error = nfsrpc_createv4(dvp, name, namelen, vap, cverf, fmode,
1882 owp, &dp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp,
1885 * There is no need to invalidate cached attributes here,
1886 * since new post-delegation issue attributes are always
1887 * returned by nfsrpc_createv4() and these will update the
1891 (void) nfscl_deleg(nmp->nm_mountp, owp->nfsow_clp,
1892 (*nfhpp)->nfh_fh, (*nfhpp)->nfh_len, cred, p, &dp);
1893 nfscl_ownerrelease(nmp, owp, error, newone, unlocked);
1894 if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
1895 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1896 error == NFSERR_BADSESSION) {
1897 (void) nfs_catnap(PZERO, error, "nfs_open");
1898 } else if ((error == NFSERR_EXPIRED ||
1899 error == NFSERR_BADSTATEID) && clidrev != 0) {
1900 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1903 } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
1904 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1905 error == NFSERR_BADSESSION ||
1906 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1907 expireret == 0 && clidrev != 0 && retrycnt < 4));
1908 if (error && retrycnt >= 4)
1911 error = nfsrpc_createv23(dvp, name, namelen, vap, cverf,
1912 fmode, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp,
1919 * The create rpc for v2 and 3.
1922 nfsrpc_createv23(vnode_t dvp, char *name, int namelen, struct vattr *vap,
1923 nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p,
1924 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
1925 int *attrflagp, int *dattrflagp, void *dstuff)
1929 struct nfsrv_descript nfsd, *nd = &nfsd;
1934 if (namelen > NFS_MAXNAMLEN)
1935 return (ENAMETOOLONG);
1936 NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp);
1937 (void) nfsm_strtom(nd, name, namelen);
1938 if (nd->nd_flag & ND_NFSV3) {
1939 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1940 if (fmode & O_EXCL) {
1941 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE);
1942 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
1943 *tl++ = cverf.lval[0];
1944 *tl = cverf.lval[1];
1946 *tl = txdr_unsigned(NFSCREATE_UNCHECKED);
1947 nfscl_fillsattr(nd, vap, dvp, 0, 0);
1950 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZE0, 0);
1952 error = nfscl_request(nd, dvp, p, cred, dstuff);
1955 if (nd->nd_repstat == 0) {
1956 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
1960 if (nd->nd_flag & ND_NFSV3)
1961 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
1962 if (nd->nd_repstat != 0 && error == 0)
1963 error = nd->nd_repstat;
1965 mbuf_freem(nd->nd_mrep);
1970 nfsrpc_createv4(vnode_t dvp, char *name, int namelen, struct vattr *vap,
1971 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp,
1972 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
1973 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
1974 int *dattrflagp, void *dstuff, int *unlockedp)
1977 int error = 0, deleg, newone, ret, acesize, limitby;
1978 struct nfsrv_descript nfsd, *nd = &nfsd;
1979 struct nfsclopen *op;
1980 struct nfscldeleg *dp = NULL;
1983 nfsattrbit_t attrbits;
1984 nfsv4stateid_t stateid;
1986 struct nfsmount *nmp;
1987 struct nfsclsession *tsep;
1989 nmp = VFSTONFS(dvp->v_mount);
1996 if (namelen > NFS_MAXNAMLEN)
1997 return (ENAMETOOLONG);
1998 NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp);
2000 * For V4, this is actually an Open op.
2002 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2003 *tl++ = txdr_unsigned(owp->nfsow_seqid);
2004 *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
2005 NFSV4OPEN_ACCESSREAD);
2006 *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE);
2007 tsep = nfsmnt_mdssession(nmp);
2008 *tl++ = tsep->nfsess_clientid.lval[0];
2009 *tl = tsep->nfsess_clientid.lval[1];
2010 (void) nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN);
2011 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2012 *tl++ = txdr_unsigned(NFSV4OPEN_CREATE);
2013 if (fmode & O_EXCL) {
2014 if (NFSHASNFSV4N(nmp)) {
2015 if (NFSHASSESSPERSIST(nmp)) {
2016 /* Use GUARDED for persistent sessions. */
2017 *tl = txdr_unsigned(NFSCREATE_GUARDED);
2018 nfscl_fillsattr(nd, vap, dvp, 0, 0);
2020 /* Otherwise, use EXCLUSIVE4_1. */
2021 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41);
2022 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2023 *tl++ = cverf.lval[0];
2024 *tl = cverf.lval[1];
2025 nfscl_fillsattr(nd, vap, dvp, 0, 0);
2029 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE);
2030 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2031 *tl++ = cverf.lval[0];
2032 *tl = cverf.lval[1];
2035 *tl = txdr_unsigned(NFSCREATE_UNCHECKED);
2036 nfscl_fillsattr(nd, vap, dvp, 0, 0);
2038 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2039 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
2040 (void) nfsm_strtom(nd, name, namelen);
2041 /* Get the new file's handle and attributes. */
2042 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2043 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
2044 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2045 NFSGETATTR_ATTRBIT(&attrbits);
2046 (void) nfsrv_putattrbit(nd, &attrbits);
2047 /* Get the directory's post-op attributes. */
2048 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2049 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2050 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0);
2051 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2052 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2053 (void) nfsrv_putattrbit(nd, &attrbits);
2054 error = nfscl_request(nd, dvp, p, cred, dstuff);
2057 NFSCL_INCRSEQID(owp->nfsow_seqid, nd);
2058 if (nd->nd_repstat == 0) {
2059 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
2061 stateid.seqid = *tl++;
2062 stateid.other[0] = *tl++;
2063 stateid.other[1] = *tl++;
2064 stateid.other[2] = *tl;
2065 rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
2066 (void) nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
2067 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2068 deleg = fxdr_unsigned(int, *tl);
2069 if (deleg == NFSV4OPEN_DELEGATEREAD ||
2070 deleg == NFSV4OPEN_DELEGATEWRITE) {
2071 if (!(owp->nfsow_clp->nfsc_flags &
2072 NFSCLFLAGS_FIRSTDELEG))
2073 owp->nfsow_clp->nfsc_flags |=
2074 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
2075 MALLOC(dp, struct nfscldeleg *,
2076 sizeof (struct nfscldeleg) + NFSX_V4FHMAX,
2077 M_NFSCLDELEG, M_WAITOK);
2078 LIST_INIT(&dp->nfsdl_owner);
2079 LIST_INIT(&dp->nfsdl_lock);
2080 dp->nfsdl_clp = owp->nfsow_clp;
2081 newnfs_copyincred(cred, &dp->nfsdl_cred);
2082 nfscl_lockinit(&dp->nfsdl_rwlock);
2083 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
2085 dp->nfsdl_stateid.seqid = *tl++;
2086 dp->nfsdl_stateid.other[0] = *tl++;
2087 dp->nfsdl_stateid.other[1] = *tl++;
2088 dp->nfsdl_stateid.other[2] = *tl++;
2089 ret = fxdr_unsigned(int, *tl);
2090 if (deleg == NFSV4OPEN_DELEGATEWRITE) {
2091 dp->nfsdl_flags = NFSCLDL_WRITE;
2093 * Indicates how much the file can grow.
2095 NFSM_DISSECT(tl, u_int32_t *,
2097 limitby = fxdr_unsigned(int, *tl++);
2099 case NFSV4OPEN_LIMITSIZE:
2100 dp->nfsdl_sizelimit = fxdr_hyper(tl);
2102 case NFSV4OPEN_LIMITBLOCKS:
2103 dp->nfsdl_sizelimit =
2104 fxdr_unsigned(u_int64_t, *tl++);
2105 dp->nfsdl_sizelimit *=
2106 fxdr_unsigned(u_int64_t, *tl);
2109 error = NFSERR_BADXDR;
2113 dp->nfsdl_flags = NFSCLDL_READ;
2116 dp->nfsdl_flags |= NFSCLDL_RECALL;
2117 error = nfsrv_dissectace(nd, &dp->nfsdl_ace, &ret,
2121 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
2122 error = NFSERR_BADXDR;
2125 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
2128 /* Get rid of the PutFH and Getattr status values. */
2129 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
2130 /* Load the directory attributes. */
2131 error = nfsm_loadattr(nd, dnap);
2135 if (dp != NULL && *attrflagp) {
2136 dp->nfsdl_change = nnap->na_filerev;
2137 dp->nfsdl_modtime = nnap->na_mtime;
2138 dp->nfsdl_flags |= NFSCLDL_MODTIMESET;
2141 * We can now complete the Open state.
2145 dp->nfsdl_fhlen = nfhp->nfh_len;
2146 NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, nfhp->nfh_len);
2149 * Get an Open structure that will be
2150 * attached to the OpenOwner, acquired already.
2152 error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len,
2153 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0,
2154 cred, p, NULL, &op, &newone, NULL, 0);
2157 op->nfso_stateid = stateid;
2158 newnfs_copyincred(cred, &op->nfso_cred);
2159 if ((rflags & NFSV4OPEN_RESULTCONFIRM)) {
2161 ret = nfsrpc_openconfirm(dvp, nfhp->nfh_fh,
2162 nfhp->nfh_len, op, cred, p);
2163 if (ret == NFSERR_DELAY)
2164 (void) nfs_catnap(PZERO, ret, "nfs_create");
2165 } while (ret == NFSERR_DELAY);
2170 * If the server is handing out delegations, but we didn't
2171 * get one because an OpenConfirm was required, try the
2172 * Open again, to get a delegation. This is a harmless no-op,
2173 * from a server's point of view.
2175 if ((rflags & NFSV4OPEN_RESULTCONFIRM) &&
2176 (owp->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) &&
2177 !error && dp == NULL) {
2179 ret = nfsrpc_openrpc(VFSTONFS(vnode_mount(dvp)), dvp,
2180 np->n_fhp->nfh_fh, np->n_fhp->nfh_len,
2181 nfhp->nfh_fh, nfhp->nfh_len,
2182 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), op,
2183 name, namelen, &dp, 0, 0x0, cred, p, 0, 1);
2184 if (ret == NFSERR_DELAY)
2185 (void) nfs_catnap(PZERO, ret, "nfs_crt2");
2186 } while (ret == NFSERR_DELAY);
2189 FREE((caddr_t)dp, M_NFSCLDELEG);
2192 if (ret == NFSERR_STALECLIENTID ||
2193 ret == NFSERR_STALEDONTRECOVER ||
2194 ret == NFSERR_BADSESSION)
2198 nfscl_openrelease(nmp, op, error, newone);
2201 if (nd->nd_repstat != 0 && error == 0)
2202 error = nd->nd_repstat;
2203 if (error == NFSERR_STALECLIENTID)
2204 nfscl_initiate_recovery(owp->nfsow_clp);
2208 else if (dp != NULL)
2209 FREE((caddr_t)dp, M_NFSCLDELEG);
2210 mbuf_freem(nd->nd_mrep);
2218 nfsrpc_remove(vnode_t dvp, char *name, int namelen, vnode_t vp,
2219 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp,
2223 struct nfsrv_descript nfsd, *nd = &nfsd;
2225 struct nfsmount *nmp;
2226 nfsv4stateid_t dstateid;
2227 int error, ret = 0, i;
2230 if (namelen > NFS_MAXNAMLEN)
2231 return (ENAMETOOLONG);
2232 nmp = VFSTONFS(vnode_mount(dvp));
2234 if (NFSHASNFSV4(nmp) && ret == 0) {
2235 ret = nfscl_removedeleg(vp, p, &dstateid);
2237 NFSCL_REQSTART(nd, NFSPROC_RETDELEGREMOVE, vp);
2238 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID +
2240 if (NFSHASNFSV4N(nmp))
2243 *tl++ = dstateid.seqid;
2244 *tl++ = dstateid.other[0];
2245 *tl++ = dstateid.other[1];
2246 *tl++ = dstateid.other[2];
2247 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2249 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
2250 np->n_fhp->nfh_len, 0);
2251 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2252 *tl = txdr_unsigned(NFSV4OP_REMOVE);
2258 NFSCL_REQSTART(nd, NFSPROC_REMOVE, dvp);
2259 (void) nfsm_strtom(nd, name, namelen);
2260 error = nfscl_request(nd, dvp, p, cred, dstuff);
2263 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
2264 /* For NFSv4, parse out any Delereturn replies. */
2265 if (ret > 0 && nd->nd_repstat != 0 &&
2266 (nd->nd_flag & ND_NOMOREDATA)) {
2268 * If the Delegreturn failed, try again without
2269 * it. The server will Recall, as required.
2271 mbuf_freem(nd->nd_mrep);
2274 for (i = 0; i < (ret * 2); i++) {
2275 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
2277 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2279 nd->nd_flag |= ND_NOMOREDATA;
2282 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2284 if (nd->nd_repstat && !error)
2285 error = nd->nd_repstat;
2287 mbuf_freem(nd->nd_mrep);
2292 * Do an nfs rename rpc.
2295 nfsrpc_rename(vnode_t fdvp, vnode_t fvp, char *fnameptr, int fnamelen,
2296 vnode_t tdvp, vnode_t tvp, char *tnameptr, int tnamelen, struct ucred *cred,
2297 NFSPROC_T *p, struct nfsvattr *fnap, struct nfsvattr *tnap,
2298 int *fattrflagp, int *tattrflagp, void *fstuff, void *tstuff)
2301 struct nfsrv_descript nfsd, *nd = &nfsd;
2302 struct nfsmount *nmp;
2304 nfsattrbit_t attrbits;
2305 nfsv4stateid_t fdstateid, tdstateid;
2306 int error = 0, ret = 0, gottd = 0, gotfd = 0, i;
2310 nmp = VFSTONFS(vnode_mount(fdvp));
2311 if (fnamelen > NFS_MAXNAMLEN || tnamelen > NFS_MAXNAMLEN)
2312 return (ENAMETOOLONG);
2314 if (NFSHASNFSV4(nmp) && ret == 0) {
2315 ret = nfscl_renamedeleg(fvp, &fdstateid, &gotfd, tvp,
2316 &tdstateid, &gottd, p);
2317 if (gotfd && gottd) {
2318 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME2, fvp);
2320 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, fvp);
2322 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, tvp);
2325 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2326 if (NFSHASNFSV4N(nmp))
2329 *tl++ = fdstateid.seqid;
2330 *tl++ = fdstateid.other[0];
2331 *tl++ = fdstateid.other[1];
2332 *tl = fdstateid.other[2];
2334 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2335 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2337 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
2338 np->n_fhp->nfh_len, 0);
2339 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2340 *tl = txdr_unsigned(NFSV4OP_DELEGRETURN);
2344 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2345 if (NFSHASNFSV4N(nmp))
2348 *tl++ = tdstateid.seqid;
2349 *tl++ = tdstateid.other[0];
2350 *tl++ = tdstateid.other[1];
2351 *tl = tdstateid.other[2];
2354 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2355 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2357 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
2358 np->n_fhp->nfh_len, 0);
2359 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2360 *tl = txdr_unsigned(NFSV4OP_SAVEFH);
2366 NFSCL_REQSTART(nd, NFSPROC_RENAME, fdvp);
2367 if (nd->nd_flag & ND_NFSV4) {
2368 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2369 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2370 NFSWCCATTR_ATTRBIT(&attrbits);
2371 (void) nfsrv_putattrbit(nd, &attrbits);
2372 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2373 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2374 (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh,
2375 VTONFS(tdvp)->n_fhp->nfh_len, 0);
2376 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2377 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2378 (void) nfsrv_putattrbit(nd, &attrbits);
2379 nd->nd_flag |= ND_V4WCCATTR;
2380 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2381 *tl = txdr_unsigned(NFSV4OP_RENAME);
2383 (void) nfsm_strtom(nd, fnameptr, fnamelen);
2384 if (!(nd->nd_flag & ND_NFSV4))
2385 (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh,
2386 VTONFS(tdvp)->n_fhp->nfh_len, 0);
2387 (void) nfsm_strtom(nd, tnameptr, tnamelen);
2388 error = nfscl_request(nd, fdvp, p, cred, fstuff);
2391 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
2392 /* For NFSv4, parse out any Delereturn replies. */
2393 if (ret > 0 && nd->nd_repstat != 0 &&
2394 (nd->nd_flag & ND_NOMOREDATA)) {
2396 * If the Delegreturn failed, try again without
2397 * it. The server will Recall, as required.
2399 mbuf_freem(nd->nd_mrep);
2402 for (i = 0; i < (ret * 2); i++) {
2403 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
2405 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2407 if (i == 0 && ret > 1) {
2409 * If the Delegreturn failed, try again
2410 * without it. The server will Recall, as
2412 * If ret > 1, the first iteration of this
2413 * loop is the second DelegReturn result.
2415 mbuf_freem(nd->nd_mrep);
2418 nd->nd_flag |= ND_NOMOREDATA;
2423 /* Now, the first wcc attribute reply. */
2424 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
2425 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2427 nd->nd_flag |= ND_NOMOREDATA;
2429 error = nfscl_wcc_data(nd, fdvp, fnap, fattrflagp, NULL,
2431 /* and the second wcc attribute reply. */
2432 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 &&
2434 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2436 nd->nd_flag |= ND_NOMOREDATA;
2439 error = nfscl_wcc_data(nd, tdvp, tnap, tattrflagp,
2442 if (nd->nd_repstat && !error)
2443 error = nd->nd_repstat;
2445 mbuf_freem(nd->nd_mrep);
2450 * nfs hard link create rpc
2453 nfsrpc_link(vnode_t dvp, vnode_t vp, char *name, int namelen,
2454 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
2455 struct nfsvattr *nap, int *attrflagp, int *dattrflagp, void *dstuff)
2458 struct nfsrv_descript nfsd, *nd = &nfsd;
2459 nfsattrbit_t attrbits;
2464 if (namelen > NFS_MAXNAMLEN)
2465 return (ENAMETOOLONG);
2466 NFSCL_REQSTART(nd, NFSPROC_LINK, vp);
2467 if (nd->nd_flag & ND_NFSV4) {
2468 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2469 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2471 (void) nfsm_fhtom(nd, VTONFS(dvp)->n_fhp->nfh_fh,
2472 VTONFS(dvp)->n_fhp->nfh_len, 0);
2473 if (nd->nd_flag & ND_NFSV4) {
2474 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2475 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2476 NFSWCCATTR_ATTRBIT(&attrbits);
2477 (void) nfsrv_putattrbit(nd, &attrbits);
2478 nd->nd_flag |= ND_V4WCCATTR;
2479 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2480 *tl = txdr_unsigned(NFSV4OP_LINK);
2482 (void) nfsm_strtom(nd, name, namelen);
2483 error = nfscl_request(nd, vp, p, cred, dstuff);
2486 if (nd->nd_flag & ND_NFSV3) {
2487 error = nfscl_postop_attr(nd, nap, attrflagp, dstuff);
2489 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp,
2491 } else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
2493 * First, parse out the PutFH and Getattr result.
2495 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2497 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2499 nd->nd_flag |= ND_NOMOREDATA;
2501 * Get the pre-op attributes.
2503 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2505 if (nd->nd_repstat && !error)
2506 error = nd->nd_repstat;
2508 mbuf_freem(nd->nd_mrep);
2513 * nfs symbolic link create rpc
2516 nfsrpc_symlink(vnode_t dvp, char *name, int namelen, char *target,
2517 struct vattr *vap, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
2518 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
2519 int *dattrflagp, void *dstuff)
2522 struct nfsrv_descript nfsd, *nd = &nfsd;
2523 struct nfsmount *nmp;
2524 int slen, error = 0;
2529 nmp = VFSTONFS(vnode_mount(dvp));
2530 slen = strlen(target);
2531 if (slen > NFS_MAXPATHLEN || namelen > NFS_MAXNAMLEN)
2532 return (ENAMETOOLONG);
2533 NFSCL_REQSTART(nd, NFSPROC_SYMLINK, dvp);
2534 if (nd->nd_flag & ND_NFSV4) {
2535 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2536 *tl = txdr_unsigned(NFLNK);
2537 (void) nfsm_strtom(nd, target, slen);
2539 (void) nfsm_strtom(nd, name, namelen);
2540 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
2541 nfscl_fillsattr(nd, vap, dvp, 0, 0);
2542 if (!(nd->nd_flag & ND_NFSV4))
2543 (void) nfsm_strtom(nd, target, slen);
2544 if (nd->nd_flag & ND_NFSV2)
2545 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0);
2546 error = nfscl_request(nd, dvp, p, cred, dstuff);
2549 if (nd->nd_flag & ND_NFSV4)
2550 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2551 if ((nd->nd_flag & ND_NFSV3) && !error) {
2552 if (!nd->nd_repstat)
2553 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
2555 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp,
2558 if (nd->nd_repstat && !error)
2559 error = nd->nd_repstat;
2560 mbuf_freem(nd->nd_mrep);
2562 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
2563 * Only do this if vfs.nfs.ignore_eexist is set.
2564 * Never do this for NFSv4.1 or later minor versions, since sessions
2565 * should guarantee "exactly once" RPC semantics.
2567 if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) ||
2568 nmp->nm_minorvers == 0))
2577 nfsrpc_mkdir(vnode_t dvp, char *name, int namelen, struct vattr *vap,
2578 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
2579 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
2580 int *dattrflagp, void *dstuff)
2583 struct nfsrv_descript nfsd, *nd = &nfsd;
2584 nfsattrbit_t attrbits;
2587 struct nfsmount *nmp;
2592 nmp = VFSTONFS(vnode_mount(dvp));
2593 fhp = VTONFS(dvp)->n_fhp;
2594 if (namelen > NFS_MAXNAMLEN)
2595 return (ENAMETOOLONG);
2596 NFSCL_REQSTART(nd, NFSPROC_MKDIR, dvp);
2597 if (nd->nd_flag & ND_NFSV4) {
2598 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2599 *tl = txdr_unsigned(NFDIR);
2601 (void) nfsm_strtom(nd, name, namelen);
2602 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0);
2603 if (nd->nd_flag & ND_NFSV4) {
2604 NFSGETATTR_ATTRBIT(&attrbits);
2605 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2606 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
2607 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2608 (void) nfsrv_putattrbit(nd, &attrbits);
2609 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2610 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2611 (void) nfsm_fhtom(nd, fhp->nfh_fh, fhp->nfh_len, 0);
2612 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2613 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2614 (void) nfsrv_putattrbit(nd, &attrbits);
2616 error = nfscl_request(nd, dvp, p, cred, dstuff);
2619 if (nd->nd_flag & ND_NFSV4)
2620 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2621 if (!nd->nd_repstat && !error) {
2622 if (nd->nd_flag & ND_NFSV4) {
2623 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2624 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
2627 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
2628 if (error == 0 && (nd->nd_flag & ND_NFSV4) != 0) {
2629 /* Get rid of the PutFH and Getattr status values. */
2630 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
2631 /* Load the directory attributes. */
2632 error = nfsm_loadattr(nd, dnap);
2637 if ((nd->nd_flag & ND_NFSV3) && !error)
2638 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2639 if (nd->nd_repstat && !error)
2640 error = nd->nd_repstat;
2642 mbuf_freem(nd->nd_mrep);
2644 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
2645 * Only do this if vfs.nfs.ignore_eexist is set.
2646 * Never do this for NFSv4.1 or later minor versions, since sessions
2647 * should guarantee "exactly once" RPC semantics.
2649 if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) ||
2650 nmp->nm_minorvers == 0))
2656 * nfs remove directory call
2659 nfsrpc_rmdir(vnode_t dvp, char *name, int namelen, struct ucred *cred,
2660 NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp, void *dstuff)
2662 struct nfsrv_descript nfsd, *nd = &nfsd;
2666 if (namelen > NFS_MAXNAMLEN)
2667 return (ENAMETOOLONG);
2668 NFSCL_REQSTART(nd, NFSPROC_RMDIR, dvp);
2669 (void) nfsm_strtom(nd, name, namelen);
2670 error = nfscl_request(nd, dvp, p, cred, dstuff);
2673 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
2674 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2675 if (nd->nd_repstat && !error)
2676 error = nd->nd_repstat;
2677 mbuf_freem(nd->nd_mrep);
2679 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
2681 if (error == ENOENT)
2688 * Always returns with either uio_resid unchanged, if you are at the
2689 * end of the directory, or uio_resid == 0, with all DIRBLKSIZ chunks
2691 * I felt this would allow caching of directory blocks more easily
2692 * than returning a pertially filled block.
2693 * Directory offset cookies:
2694 * Oh my, what to do with them...
2695 * I can think of three ways to deal with them:
2696 * 1 - have the layer above these RPCs maintain a map between logical
2697 * directory byte offsets and the NFS directory offset cookies
2698 * 2 - pass the opaque directory offset cookies up into userland
2699 * and let the libc functions deal with them, via the system call
2700 * 3 - return them to userland in the "struct dirent", so future versions
2701 * of libc can use them and do whatever is necessary to amke things work
2702 * above these rpc calls, in the meantime
2703 * For now, I do #3 by "hiding" the directory offset cookies after the
2704 * d_name field in struct dirent. This is space inside d_reclen that
2705 * will be ignored by anything that doesn't know about them.
2706 * The directory offset cookies are filled in as the last 8 bytes of
2707 * each directory entry, after d_name. Someday, the userland libc
2708 * functions may be able to use these. In the meantime, it satisfies
2709 * OpenBSD's requirements for cookies being returned.
2710 * If expects the directory offset cookie for the read to be in uio_offset
2711 * and returns the one for the next entry after this directory block in
2715 nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
2716 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
2717 int *eofp, void *stuff)
2720 struct dirent *dp = NULL;
2722 nfsquad_t cookie, ncookie;
2723 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
2724 struct nfsnode *dnp = VTONFS(vp);
2725 struct nfsvattr nfsva;
2726 struct nfsrv_descript nfsd, *nd = &nfsd;
2727 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
2728 int reqsize, tryformoredirs = 1, readsize, eof = 0, gotmnton = 0;
2729 long dotfileid, dotdotfileid = 0;
2730 u_int32_t fakefileno = 0xffffffff, rderr;
2732 nfsattrbit_t attrbits, dattrbits;
2733 u_int32_t *tl2 = NULL;
2736 KASSERT(uiop->uio_iovcnt == 1 &&
2737 (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0,
2738 ("nfs readdirrpc bad uio"));
2741 * There is no point in reading a lot more than uio_resid, however
2742 * adding one additional DIRBLKSIZ makes sense. Since uio_resid
2743 * and nm_readdirsize are both exact multiples of DIRBLKSIZ, this
2744 * will never make readsize > nm_readdirsize.
2746 readsize = nmp->nm_readdirsize;
2747 if (readsize > uio_uio_resid(uiop))
2748 readsize = uio_uio_resid(uiop) + DIRBLKSIZ;
2753 tresid = uio_uio_resid(uiop);
2754 cookie.lval[0] = cookiep->nfsuquad[0];
2755 cookie.lval[1] = cookiep->nfsuquad[1];
2759 * For NFSv4, first create the "." and ".." entries.
2761 if (NFSHASNFSV4(nmp)) {
2762 reqsize = 6 * NFSX_UNSIGNED;
2763 NFSGETATTR_ATTRBIT(&dattrbits);
2764 NFSZERO_ATTRBIT(&attrbits);
2765 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID);
2766 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TYPE);
2767 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
2768 NFSATTRBIT_MOUNTEDONFILEID)) {
2769 NFSSETBIT_ATTRBIT(&attrbits,
2770 NFSATTRBIT_MOUNTEDONFILEID);
2774 * Must fake it. Use the fileno, except when the
2775 * fsid is != to that of the directory. For that
2776 * case, generate a fake fileno that is not the same.
2778 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID);
2783 * Joy, oh joy. For V4 we get to hand craft '.' and '..'.
2785 if (uiop->uio_offset == 0) {
2786 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp);
2787 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2788 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
2789 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2790 (void) nfsrv_putattrbit(nd, &attrbits);
2791 error = nfscl_request(nd, vp, p, cred, stuff);
2794 dotfileid = 0; /* Fake out the compiler. */
2795 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
2796 error = nfsm_loadattr(nd, &nfsva);
2799 dotfileid = nfsva.na_fileid;
2801 if (nd->nd_repstat == 0) {
2802 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2803 len = fxdr_unsigned(int, *(tl + 4));
2804 if (len > 0 && len <= NFSX_V4FHMAX)
2805 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
2809 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
2810 nfsva.na_mntonfileno = 0xffffffff;
2811 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
2812 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
2813 NULL, NULL, NULL, p, cred);
2815 dotdotfileid = dotfileid;
2816 } else if (gotmnton) {
2817 if (nfsva.na_mntonfileno != 0xffffffff)
2818 dotdotfileid = nfsva.na_mntonfileno;
2820 dotdotfileid = nfsva.na_fileid;
2821 } else if (nfsva.na_filesid[0] ==
2822 dnp->n_vattr.na_filesid[0] &&
2823 nfsva.na_filesid[1] ==
2824 dnp->n_vattr.na_filesid[1]) {
2825 dotdotfileid = nfsva.na_fileid;
2829 } while (fakefileno ==
2831 dotdotfileid = fakefileno;
2834 } else if (nd->nd_repstat == NFSERR_NOENT) {
2836 * Lookupp returns NFSERR_NOENT when we are
2837 * at the root, so just use the current dir.
2840 dotdotfileid = dotfileid;
2842 error = nd->nd_repstat;
2844 mbuf_freem(nd->nd_mrep);
2848 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
2849 dp->d_type = DT_DIR;
2850 dp->d_fileno = dotfileid;
2852 dp->d_name[0] = '.';
2853 dp->d_name[1] = '\0';
2854 dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
2856 * Just make these offset cookie 0.
2858 tl = (u_int32_t *)&dp->d_name[4];
2861 blksiz += dp->d_reclen;
2862 uio_uio_resid_add(uiop, -(dp->d_reclen));
2863 uiop->uio_offset += dp->d_reclen;
2864 uio_iov_base_add(uiop, dp->d_reclen);
2865 uio_iov_len_add(uiop, -(dp->d_reclen));
2866 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
2867 dp->d_type = DT_DIR;
2868 dp->d_fileno = dotdotfileid;
2870 dp->d_name[0] = '.';
2871 dp->d_name[1] = '.';
2872 dp->d_name[2] = '\0';
2873 dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
2875 * Just make these offset cookie 0.
2877 tl = (u_int32_t *)&dp->d_name[4];
2880 blksiz += dp->d_reclen;
2881 uio_uio_resid_add(uiop, -(dp->d_reclen));
2882 uiop->uio_offset += dp->d_reclen;
2883 uio_iov_base_add(uiop, dp->d_reclen);
2884 uio_iov_len_add(uiop, -(dp->d_reclen));
2886 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_RDATTRERROR);
2888 reqsize = 5 * NFSX_UNSIGNED;
2893 * Loop around doing readdir rpc's of size readsize.
2894 * The stopping criteria is EOF or buffer full.
2896 while (more_dirs && bigenough) {
2898 NFSCL_REQSTART(nd, NFSPROC_READDIR, vp);
2899 if (nd->nd_flag & ND_NFSV2) {
2900 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2901 *tl++ = cookie.lval[1];
2902 *tl = txdr_unsigned(readsize);
2904 NFSM_BUILD(tl, u_int32_t *, reqsize);
2905 *tl++ = cookie.lval[0];
2906 *tl++ = cookie.lval[1];
2907 if (cookie.qval == 0) {
2912 *tl++ = dnp->n_cookieverf.nfsuquad[0];
2913 *tl++ = dnp->n_cookieverf.nfsuquad[1];
2916 if (nd->nd_flag & ND_NFSV4) {
2917 *tl++ = txdr_unsigned(readsize);
2918 *tl = txdr_unsigned(readsize);
2919 (void) nfsrv_putattrbit(nd, &attrbits);
2920 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2921 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2922 (void) nfsrv_putattrbit(nd, &dattrbits);
2924 *tl = txdr_unsigned(readsize);
2927 error = nfscl_request(nd, vp, p, cred, stuff);
2930 if (!(nd->nd_flag & ND_NFSV2)) {
2931 if (nd->nd_flag & ND_NFSV3)
2932 error = nfscl_postop_attr(nd, nap, attrflagp,
2934 if (!nd->nd_repstat && !error) {
2935 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2937 dnp->n_cookieverf.nfsuquad[0] = *tl++;
2938 dnp->n_cookieverf.nfsuquad[1] = *tl;
2942 if (nd->nd_repstat || error) {
2944 error = nd->nd_repstat;
2947 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2948 more_dirs = fxdr_unsigned(int, *tl);
2952 /* loop thru the dir entries, doctoring them to 4bsd form */
2953 while (more_dirs && bigenough) {
2954 if (nd->nd_flag & ND_NFSV4) {
2955 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
2956 ncookie.lval[0] = *tl++;
2957 ncookie.lval[1] = *tl++;
2958 len = fxdr_unsigned(int, *tl);
2959 } else if (nd->nd_flag & ND_NFSV3) {
2960 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
2961 nfsva.na_fileid = fxdr_hyper(tl);
2963 len = fxdr_unsigned(int, *tl);
2965 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
2967 fxdr_unsigned(long, *tl++);
2968 len = fxdr_unsigned(int, *tl);
2970 if (len <= 0 || len > NFS_MAXNAMLEN) {
2974 tlen = NFSM_RNDUP(len);
2976 tlen += 4; /* To ensure null termination */
2977 left = DIRBLKSIZ - blksiz;
2978 if ((int)(tlen + DIRHDSIZ + NFSX_HYPER) > left) {
2979 dp->d_reclen += left;
2980 uio_iov_base_add(uiop, left);
2981 uio_iov_len_add(uiop, -(left));
2982 uio_uio_resid_add(uiop, -(left));
2983 uiop->uio_offset += left;
2986 if ((int)(tlen + DIRHDSIZ + NFSX_HYPER) > uio_uio_resid(uiop))
2989 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
2991 dp->d_reclen = tlen + DIRHDSIZ + NFSX_HYPER;
2992 dp->d_type = DT_UNKNOWN;
2993 blksiz += dp->d_reclen;
2994 if (blksiz == DIRBLKSIZ)
2996 uio_uio_resid_add(uiop, -(DIRHDSIZ));
2997 uiop->uio_offset += DIRHDSIZ;
2998 uio_iov_base_add(uiop, DIRHDSIZ);
2999 uio_iov_len_add(uiop, -(DIRHDSIZ));
3000 error = nfsm_mbufuio(nd, uiop, len);
3003 cp = CAST_DOWN(caddr_t, uio_iov_base(uiop));
3005 *cp = '\0'; /* null terminate */
3006 cp += tlen; /* points to cookie storage */
3007 tl2 = (u_int32_t *)cp;
3008 uio_iov_base_add(uiop, (tlen + NFSX_HYPER));
3009 uio_iov_len_add(uiop, -(tlen + NFSX_HYPER));
3010 uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER));
3011 uiop->uio_offset += (tlen + NFSX_HYPER);
3013 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
3017 if (nd->nd_flag & ND_NFSV4) {
3019 nfsva.na_mntonfileno = 0xffffffff;
3020 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
3021 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
3022 NULL, NULL, &rderr, p, cred);
3025 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3026 } else if (nd->nd_flag & ND_NFSV3) {
3027 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3028 ncookie.lval[0] = *tl++;
3029 ncookie.lval[1] = *tl++;
3031 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
3032 ncookie.lval[0] = 0;
3033 ncookie.lval[1] = *tl++;
3036 if (nd->nd_flag & ND_NFSV4) {
3041 if (nfsva.na_mntonfileno != 0xffffffff)
3042 dp->d_fileno = nfsva.na_mntonfileno;
3044 dp->d_fileno = nfsva.na_fileid;
3045 } else if (nfsva.na_filesid[0] ==
3046 dnp->n_vattr.na_filesid[0] &&
3047 nfsva.na_filesid[1] ==
3048 dnp->n_vattr.na_filesid[1]) {
3049 dp->d_fileno = nfsva.na_fileid;
3053 } while (fakefileno ==
3055 dp->d_fileno = fakefileno;
3057 dp->d_type = vtonfs_dtype(nfsva.na_type);
3060 dp->d_fileno = nfsva.na_fileid;
3062 *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] =
3064 *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] =
3067 more_dirs = fxdr_unsigned(int, *tl);
3070 * If at end of rpc data, get the eof boolean
3073 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3074 eof = fxdr_unsigned(int, *tl);
3077 if (nd->nd_flag & ND_NFSV4) {
3078 error = nfscl_postop_attr(nd, nap, attrflagp,
3084 mbuf_freem(nd->nd_mrep);
3088 * Fill last record, iff any, out to a multiple of DIRBLKSIZ
3089 * by increasing d_reclen for the last record.
3092 left = DIRBLKSIZ - blksiz;
3093 dp->d_reclen += left;
3094 uio_iov_base_add(uiop, left);
3095 uio_iov_len_add(uiop, -(left));
3096 uio_uio_resid_add(uiop, -(left));
3097 uiop->uio_offset += left;
3101 * If returning no data, assume end of file.
3102 * If not bigenough, return not end of file, since you aren't
3103 * returning all the data
3104 * Otherwise, return the eof flag from the server.
3107 if (tresid == ((size_t)(uio_uio_resid(uiop))))
3109 else if (!bigenough)
3116 * Add extra empty records to any remaining DIRBLKSIZ chunks.
3118 while (uio_uio_resid(uiop) > 0 && ((size_t)(uio_uio_resid(uiop))) != tresid) {
3119 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
3120 dp->d_type = DT_UNKNOWN;
3123 dp->d_name[0] = '\0';
3124 tl = (u_int32_t *)&dp->d_name[4];
3125 *tl++ = cookie.lval[0];
3126 *tl = cookie.lval[1];
3127 dp->d_reclen = DIRBLKSIZ;
3128 uio_iov_base_add(uiop, DIRBLKSIZ);
3129 uio_iov_len_add(uiop, -(DIRBLKSIZ));
3130 uio_uio_resid_add(uiop, -(DIRBLKSIZ));
3131 uiop->uio_offset += DIRBLKSIZ;
3135 if (nd->nd_mrep != NULL)
3136 mbuf_freem(nd->nd_mrep);
3142 * NFS V3 readdir plus RPC. Used in place of nfsrpc_readdir().
3143 * (Also used for NFS V4 when mount flag set.)
3144 * (ditto above w.r.t. multiple of DIRBLKSIZ, etc.)
3147 nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
3148 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
3149 int *eofp, void *stuff)
3152 struct dirent *dp = NULL;
3154 vnode_t newvp = NULLVP;
3155 struct nfsrv_descript nfsd, *nd = &nfsd;
3156 struct nameidata nami, *ndp = &nami;
3157 struct componentname *cnp = &ndp->ni_cnd;
3158 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
3159 struct nfsnode *dnp = VTONFS(vp), *np;
3160 struct nfsvattr nfsva;
3162 nfsquad_t cookie, ncookie;
3163 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
3164 int attrflag, tryformoredirs = 1, eof = 0, gotmnton = 0;
3165 int isdotdot = 0, unlocknewvp = 0;
3166 long dotfileid, dotdotfileid = 0, fileno = 0;
3168 nfsattrbit_t attrbits, dattrbits;
3170 u_int32_t *tl2 = NULL, fakefileno = 0xffffffff, rderr;
3171 struct timespec dctime;
3173 KASSERT(uiop->uio_iovcnt == 1 &&
3174 (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0,
3175 ("nfs readdirplusrpc bad uio"));
3176 timespecclear(&dctime);
3182 cookie.lval[0] = cookiep->nfsuquad[0];
3183 cookie.lval[1] = cookiep->nfsuquad[1];
3184 tresid = uio_uio_resid(uiop);
3187 * For NFSv4, first create the "." and ".." entries.
3189 if (NFSHASNFSV4(nmp)) {
3190 NFSGETATTR_ATTRBIT(&dattrbits);
3191 NFSZERO_ATTRBIT(&attrbits);
3192 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID);
3193 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
3194 NFSATTRBIT_MOUNTEDONFILEID)) {
3195 NFSSETBIT_ATTRBIT(&attrbits,
3196 NFSATTRBIT_MOUNTEDONFILEID);
3200 * Must fake it. Use the fileno, except when the
3201 * fsid is != to that of the directory. For that
3202 * case, generate a fake fileno that is not the same.
3204 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID);
3209 * Joy, oh joy. For V4 we get to hand craft '.' and '..'.
3211 if (uiop->uio_offset == 0) {
3212 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp);
3213 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3214 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
3215 *tl = txdr_unsigned(NFSV4OP_GETATTR);
3216 (void) nfsrv_putattrbit(nd, &attrbits);
3217 error = nfscl_request(nd, vp, p, cred, stuff);
3220 dotfileid = 0; /* Fake out the compiler. */
3221 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
3222 error = nfsm_loadattr(nd, &nfsva);
3225 dctime = nfsva.na_ctime;
3226 dotfileid = nfsva.na_fileid;
3228 if (nd->nd_repstat == 0) {
3229 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
3230 len = fxdr_unsigned(int, *(tl + 4));
3231 if (len > 0 && len <= NFSX_V4FHMAX)
3232 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
3236 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
3237 nfsva.na_mntonfileno = 0xffffffff;
3238 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
3239 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
3240 NULL, NULL, NULL, p, cred);
3242 dotdotfileid = dotfileid;
3243 } else if (gotmnton) {
3244 if (nfsva.na_mntonfileno != 0xffffffff)
3245 dotdotfileid = nfsva.na_mntonfileno;
3247 dotdotfileid = nfsva.na_fileid;
3248 } else if (nfsva.na_filesid[0] ==
3249 dnp->n_vattr.na_filesid[0] &&
3250 nfsva.na_filesid[1] ==
3251 dnp->n_vattr.na_filesid[1]) {
3252 dotdotfileid = nfsva.na_fileid;
3256 } while (fakefileno ==
3258 dotdotfileid = fakefileno;
3261 } else if (nd->nd_repstat == NFSERR_NOENT) {
3263 * Lookupp returns NFSERR_NOENT when we are
3264 * at the root, so just use the current dir.
3267 dotdotfileid = dotfileid;
3269 error = nd->nd_repstat;
3271 mbuf_freem(nd->nd_mrep);
3275 dp = (struct dirent *)uio_iov_base(uiop);
3276 dp->d_type = DT_DIR;
3277 dp->d_fileno = dotfileid;
3279 dp->d_name[0] = '.';
3280 dp->d_name[1] = '\0';
3281 dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
3283 * Just make these offset cookie 0.
3285 tl = (u_int32_t *)&dp->d_name[4];
3288 blksiz += dp->d_reclen;
3289 uio_uio_resid_add(uiop, -(dp->d_reclen));
3290 uiop->uio_offset += dp->d_reclen;
3291 uio_iov_base_add(uiop, dp->d_reclen);
3292 uio_iov_len_add(uiop, -(dp->d_reclen));
3293 dp = (struct dirent *)uio_iov_base(uiop);
3294 dp->d_type = DT_DIR;
3295 dp->d_fileno = dotdotfileid;
3297 dp->d_name[0] = '.';
3298 dp->d_name[1] = '.';
3299 dp->d_name[2] = '\0';
3300 dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
3302 * Just make these offset cookie 0.
3304 tl = (u_int32_t *)&dp->d_name[4];
3307 blksiz += dp->d_reclen;
3308 uio_uio_resid_add(uiop, -(dp->d_reclen));
3309 uiop->uio_offset += dp->d_reclen;
3310 uio_iov_base_add(uiop, dp->d_reclen);
3311 uio_iov_len_add(uiop, -(dp->d_reclen));
3313 NFSREADDIRPLUS_ATTRBIT(&attrbits);
3315 NFSSETBIT_ATTRBIT(&attrbits,
3316 NFSATTRBIT_MOUNTEDONFILEID);
3320 * Loop around doing readdir rpc's of size nm_readdirsize.
3321 * The stopping criteria is EOF or buffer full.
3323 while (more_dirs && bigenough) {
3325 NFSCL_REQSTART(nd, NFSPROC_READDIRPLUS, vp);
3326 NFSM_BUILD(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
3327 *tl++ = cookie.lval[0];
3328 *tl++ = cookie.lval[1];
3329 if (cookie.qval == 0) {
3334 *tl++ = dnp->n_cookieverf.nfsuquad[0];
3335 *tl++ = dnp->n_cookieverf.nfsuquad[1];
3338 *tl++ = txdr_unsigned(nmp->nm_readdirsize);
3339 *tl = txdr_unsigned(nmp->nm_readdirsize);
3340 if (nd->nd_flag & ND_NFSV4) {
3341 (void) nfsrv_putattrbit(nd, &attrbits);
3342 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3343 *tl = txdr_unsigned(NFSV4OP_GETATTR);
3344 (void) nfsrv_putattrbit(nd, &dattrbits);
3346 error = nfscl_request(nd, vp, p, cred, stuff);
3349 if (nd->nd_flag & ND_NFSV3)
3350 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3351 if (nd->nd_repstat || error) {
3353 error = nd->nd_repstat;
3356 if ((nd->nd_flag & ND_NFSV3) != 0 && *attrflagp != 0)
3357 dctime = nap->na_ctime;
3358 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3360 dnp->n_cookieverf.nfsuquad[0] = *tl++;
3361 dnp->n_cookieverf.nfsuquad[1] = *tl++;
3363 more_dirs = fxdr_unsigned(int, *tl);
3367 /* loop thru the dir entries, doctoring them to 4bsd form */
3368 while (more_dirs && bigenough) {
3369 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3370 if (nd->nd_flag & ND_NFSV4) {
3371 ncookie.lval[0] = *tl++;
3372 ncookie.lval[1] = *tl++;
3374 fileno = fxdr_unsigned(long, *++tl);
3377 len = fxdr_unsigned(int, *tl);
3378 if (len <= 0 || len > NFS_MAXNAMLEN) {
3382 tlen = NFSM_RNDUP(len);
3384 tlen += 4; /* To ensure null termination */
3385 left = DIRBLKSIZ - blksiz;
3386 if ((tlen + DIRHDSIZ + NFSX_HYPER) > left) {
3387 dp->d_reclen += left;
3388 uio_iov_base_add(uiop, left);
3389 uio_iov_len_add(uiop, -(left));
3390 uio_uio_resid_add(uiop, -(left));
3391 uiop->uio_offset += left;
3394 if ((tlen + DIRHDSIZ + NFSX_HYPER) > uio_uio_resid(uiop))
3397 dp = (struct dirent *)uio_iov_base(uiop);
3399 dp->d_reclen = tlen + DIRHDSIZ + NFSX_HYPER;
3400 dp->d_type = DT_UNKNOWN;
3401 blksiz += dp->d_reclen;
3402 if (blksiz == DIRBLKSIZ)
3404 uio_uio_resid_add(uiop, -(DIRHDSIZ));
3405 uiop->uio_offset += DIRHDSIZ;
3406 uio_iov_base_add(uiop, DIRHDSIZ);
3407 uio_iov_len_add(uiop, -(DIRHDSIZ));
3408 cnp->cn_nameptr = uio_iov_base(uiop);
3409 cnp->cn_namelen = len;
3411 error = nfsm_mbufuio(nd, uiop, len);
3414 cp = uio_iov_base(uiop);
3417 cp += tlen; /* points to cookie storage */
3418 tl2 = (u_int32_t *)cp;
3419 if (len == 2 && cnp->cn_nameptr[0] == '.' &&
3420 cnp->cn_nameptr[1] == '.')
3424 uio_iov_base_add(uiop, (tlen + NFSX_HYPER));
3425 uio_iov_len_add(uiop, -(tlen + NFSX_HYPER));
3426 uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER));
3427 uiop->uio_offset += (tlen + NFSX_HYPER);
3429 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
3434 if (nd->nd_flag & ND_NFSV3) {
3435 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3436 ncookie.lval[0] = *tl++;
3437 ncookie.lval[1] = *tl++;
3438 attrflag = fxdr_unsigned(int, *tl);
3440 error = nfsm_loadattr(nd, &nfsva);
3444 NFSM_DISSECT(tl,u_int32_t *,NFSX_UNSIGNED);
3446 error = nfsm_getfh(nd, &nfhp);
3450 if (!attrflag && nfhp != NULL) {
3451 FREE((caddr_t)nfhp, M_NFSFH);
3456 nfsva.na_mntonfileno = 0xffffffff;
3457 error = nfsv4_loadattr(nd, NULL, &nfsva, &nfhp,
3458 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
3459 NULL, NULL, &rderr, p, cred);
3465 if (nd->nd_flag & ND_NFSV4) {
3468 } else if (gotmnton) {
3469 if (nfsva.na_mntonfileno != 0xffffffff)
3470 dp->d_fileno = nfsva.na_mntonfileno;
3472 dp->d_fileno = nfsva.na_fileid;
3473 } else if (nfsva.na_filesid[0] ==
3474 dnp->n_vattr.na_filesid[0] &&
3475 nfsva.na_filesid[1] ==
3476 dnp->n_vattr.na_filesid[1]) {
3477 dp->d_fileno = nfsva.na_fileid;
3481 } while (fakefileno ==
3483 dp->d_fileno = fakefileno;
3486 dp->d_fileno = fileno;
3488 *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] =
3490 *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] =
3494 if (NFSRV_CMPFH(nfhp->nfh_fh, nfhp->nfh_len,
3495 dnp->n_fhp->nfh_fh, dnp->n_fhp->nfh_len)) {
3499 FREE((caddr_t)nfhp, M_NFSFH);
3501 } else if (isdotdot != 0) {
3503 * Skip doing a nfscl_nget() call for "..".
3504 * There's a race between acquiring the nfs
3505 * node here and lookups that look for the
3506 * directory being read (in the parent).
3507 * It would try to get a lock on ".." here,
3508 * owning the lock on the directory being
3509 * read. Lookup will hold the lock on ".."
3510 * and try to acquire the lock on the
3511 * directory being read.
3512 * If the directory is unlocked/relocked,
3513 * then there is a LOR with the buflock
3516 free(nfhp, M_NFSFH);
3518 error = nfscl_nget(vnode_mount(vp), vp,
3519 nfhp, cnp, p, &np, NULL, LK_EXCLUSIVE);
3526 if (newvp != NULLVP) {
3527 error = nfscl_loadattrcache(&newvp,
3528 &nfsva, NULL, NULL, 0, 0);
3537 vtonfs_dtype(np->n_vattr.na_type);
3539 NFSCNHASH(cnp, HASHINIT);
3540 if (cnp->cn_namelen <= NCHNAMLEN &&
3541 (newvp->v_type != VDIR ||
3542 dctime.tv_sec != 0)) {
3543 cache_enter_time(ndp->ni_dvp,
3546 newvp->v_type != VDIR ? NULL :
3556 } else if (nfhp != NULL) {
3557 FREE((caddr_t)nfhp, M_NFSFH);
3559 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3560 more_dirs = fxdr_unsigned(int, *tl);
3563 * If at end of rpc data, get the eof boolean
3566 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3567 eof = fxdr_unsigned(int, *tl);
3570 if (nd->nd_flag & ND_NFSV4) {
3571 error = nfscl_postop_attr(nd, nap, attrflagp,
3577 mbuf_freem(nd->nd_mrep);
3581 * Fill last record, iff any, out to a multiple of DIRBLKSIZ
3582 * by increasing d_reclen for the last record.
3585 left = DIRBLKSIZ - blksiz;
3586 dp->d_reclen += left;
3587 uio_iov_base_add(uiop, left);
3588 uio_iov_len_add(uiop, -(left));
3589 uio_uio_resid_add(uiop, -(left));
3590 uiop->uio_offset += left;
3594 * If returning no data, assume end of file.
3595 * If not bigenough, return not end of file, since you aren't
3596 * returning all the data
3597 * Otherwise, return the eof flag from the server.
3600 if (tresid == uio_uio_resid(uiop))
3602 else if (!bigenough)
3609 * Add extra empty records to any remaining DIRBLKSIZ chunks.
3611 while (uio_uio_resid(uiop) > 0 && uio_uio_resid(uiop) != tresid) {
3612 dp = (struct dirent *)uio_iov_base(uiop);
3613 dp->d_type = DT_UNKNOWN;
3616 dp->d_name[0] = '\0';
3617 tl = (u_int32_t *)&dp->d_name[4];
3618 *tl++ = cookie.lval[0];
3619 *tl = cookie.lval[1];
3620 dp->d_reclen = DIRBLKSIZ;
3621 uio_iov_base_add(uiop, DIRBLKSIZ);
3622 uio_iov_len_add(uiop, -(DIRBLKSIZ));
3623 uio_uio_resid_add(uiop, -(DIRBLKSIZ));
3624 uiop->uio_offset += DIRBLKSIZ;
3628 if (nd->nd_mrep != NULL)
3629 mbuf_freem(nd->nd_mrep);
3638 nfsrpc_commit(vnode_t vp, u_quad_t offset, int cnt, struct ucred *cred,
3639 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
3642 struct nfsrv_descript nfsd, *nd = &nfsd;
3643 nfsattrbit_t attrbits;
3645 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
3648 NFSCL_REQSTART(nd, NFSPROC_COMMIT, vp);
3649 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3650 txdr_hyper(offset, tl);
3652 *tl = txdr_unsigned(cnt);
3653 if (nd->nd_flag & ND_NFSV4) {
3655 * And do a Getattr op.
3657 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3658 *tl = txdr_unsigned(NFSV4OP_GETATTR);
3659 NFSGETATTR_ATTRBIT(&attrbits);
3660 (void) nfsrv_putattrbit(nd, &attrbits);
3662 error = nfscl_request(nd, vp, p, cred, stuff);
3665 error = nfscl_wcc_data(nd, vp, nap, attrflagp, NULL, stuff);
3666 if (!error && !nd->nd_repstat) {
3667 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
3669 if (NFSBCMP(nmp->nm_verf, tl, NFSX_VERF)) {
3670 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
3671 nd->nd_repstat = NFSERR_STALEWRITEVERF;
3674 if (nd->nd_flag & ND_NFSV4)
3675 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3678 if (!error && nd->nd_repstat)
3679 error = nd->nd_repstat;
3680 mbuf_freem(nd->nd_mrep);
3685 * NFS byte range lock rpc.
3686 * (Mostly just calls one of the three lower level RPC routines.)
3689 nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
3690 int reclaim, struct ucred *cred, NFSPROC_T *p, void *id, int flags)
3692 struct nfscllockowner *lp;
3693 struct nfsclclient *clp;
3695 struct nfsrv_descript nfsd, *nd = &nfsd;
3696 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
3699 u_int32_t clidrev = 0;
3700 int error = 0, newone = 0, expireret = 0, retrycnt, donelocally;
3704 * Convert the flock structure into a start and end and do POSIX
3707 switch (fl->l_whence) {
3711 * Caller is responsible for adding any necessary offset
3712 * when SEEK_CUR is used.
3714 start = fl->l_start;
3718 start = size + fl->l_start;
3719 off = size + fl->l_start;
3726 if (fl->l_len != 0) {
3727 end = start + fl->l_len - 1;
3738 if (op == F_GETLK) {
3739 error = nfscl_getcl(vnode_mount(vp), cred, p, 1, &clp);
3742 error = nfscl_lockt(vp, clp, off, len, fl, p, id, flags);
3744 clidrev = clp->nfsc_clientidrev;
3745 error = nfsrpc_lockt(nd, vp, clp, off, len, fl, cred,
3747 } else if (error == -1) {
3750 nfscl_clientrelease(clp);
3751 } else if (op == F_UNLCK && fl->l_type == F_UNLCK) {
3753 * We must loop around for all lockowner cases.
3756 error = nfscl_getcl(vnode_mount(vp), cred, p, 1, &clp);
3760 error = nfscl_relbytelock(vp, off, len, cred, p, callcnt,
3761 clp, id, flags, &lp, &dorpc);
3763 * If it returns a NULL lp, we're done.
3767 nfscl_clientrelease(clp);
3769 nfscl_releasealllocks(clp, vp, p, id, flags);
3772 if (nmp->nm_clp != NULL)
3773 clidrev = nmp->nm_clp->nfsc_clientidrev;
3777 * If the server doesn't support Posix lock semantics,
3778 * only allow locks on the entire file, since it won't
3779 * handle overlapping byte ranges.
3780 * There might still be a problem when a lock
3781 * upgrade/downgrade (read<->write) occurs, since the
3782 * server "might" expect an unlock first?
3784 if (dorpc && (lp->nfsl_open->nfso_posixlock ||
3785 (off == 0 && len == NFS64BITSSET))) {
3787 * Since the lock records will go away, we must
3788 * wait for grace and delay here.
3791 error = nfsrpc_locku(nd, nmp, lp, off, len,
3792 NFSV4LOCKT_READ, cred, p, 0);
3793 if ((nd->nd_repstat == NFSERR_GRACE ||
3794 nd->nd_repstat == NFSERR_DELAY) &&
3796 (void) nfs_catnap(PZERO, (int)nd->nd_repstat,
3798 } while ((nd->nd_repstat == NFSERR_GRACE ||
3799 nd->nd_repstat == NFSERR_DELAY) && error == 0);
3802 } while (error == 0 && nd->nd_repstat == 0);
3803 nfscl_releasealllocks(clp, vp, p, id, flags);
3804 } else if (op == F_SETLK) {
3805 error = nfscl_getbytelock(vp, off, len, fl->l_type, cred, p,
3806 NULL, 0, id, flags, NULL, NULL, &lp, &newone, &donelocally);
3807 if (error || donelocally) {
3810 if (nmp->nm_clp != NULL)
3811 clidrev = nmp->nm_clp->nfsc_clientidrev;
3814 nfhp = VTONFS(vp)->n_fhp;
3815 if (!lp->nfsl_open->nfso_posixlock &&
3816 (off != 0 || len != NFS64BITSSET)) {
3819 error = nfsrpc_lock(nd, nmp, vp, nfhp->nfh_fh,
3820 nfhp->nfh_len, lp, newone, reclaim, off,
3821 len, fl->l_type, cred, p, 0);
3824 error = nd->nd_repstat;
3825 nfscl_lockrelease(lp, error, newone);
3830 error = nd->nd_repstat;
3831 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
3832 error == NFSERR_STALEDONTRECOVER ||
3833 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY ||
3834 error == NFSERR_BADSESSION) {
3835 (void) nfs_catnap(PZERO, error, "nfs_advlock");
3836 } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID)
3838 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
3841 } while (error == NFSERR_GRACE ||
3842 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY ||
3843 error == NFSERR_STALEDONTRECOVER || error == NFSERR_STALESTATEID ||
3844 error == NFSERR_BADSESSION ||
3845 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
3846 expireret == 0 && clidrev != 0 && retrycnt < 4));
3847 if (error && retrycnt >= 4)
3853 * The lower level routine for the LockT case.
3856 nfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp,
3857 struct nfsclclient *clp, u_int64_t off, u_int64_t len, struct flock *fl,
3858 struct ucred *cred, NFSPROC_T *p, void *id, int flags)
3861 int error, type, size;
3862 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
3864 struct nfsmount *nmp;
3865 struct nfsclsession *tsep;
3867 nmp = VFSTONFS(vp->v_mount);
3868 NFSCL_REQSTART(nd, NFSPROC_LOCKT, vp);
3869 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
3870 if (fl->l_type == F_RDLCK)
3871 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
3873 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
3874 txdr_hyper(off, tl);
3876 txdr_hyper(len, tl);
3878 tsep = nfsmnt_mdssession(nmp);
3879 *tl++ = tsep->nfsess_clientid.lval[0];
3880 *tl = tsep->nfsess_clientid.lval[1];
3881 nfscl_filllockowner(id, own, flags);
3883 NFSBCOPY(np->n_fhp->nfh_fh, &own[NFSV4CL_LOCKNAMELEN],
3884 np->n_fhp->nfh_len);
3885 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + np->n_fhp->nfh_len);
3886 error = nfscl_request(nd, vp, p, cred, NULL);
3889 if (nd->nd_repstat == 0) {
3890 fl->l_type = F_UNLCK;
3891 } else if (nd->nd_repstat == NFSERR_DENIED) {
3893 fl->l_whence = SEEK_SET;
3894 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
3895 fl->l_start = fxdr_hyper(tl);
3897 len = fxdr_hyper(tl);
3899 if (len == NFS64BITSSET)
3903 type = fxdr_unsigned(int, *tl++);
3904 if (type == NFSV4LOCKT_WRITE)
3905 fl->l_type = F_WRLCK;
3907 fl->l_type = F_RDLCK;
3909 * XXX For now, I have no idea what to do with the
3910 * conflicting lock_owner, so I'll just set the pid == 0
3911 * and skip over the lock_owner.
3913 fl->l_pid = (pid_t)0;
3915 size = fxdr_unsigned(int, *tl);
3916 if (size < 0 || size > NFSV4_OPAQUELIMIT)
3919 error = nfsm_advance(nd, NFSM_RNDUP(size), -1);
3920 } else if (nd->nd_repstat == NFSERR_STALECLIENTID)
3921 nfscl_initiate_recovery(clp);
3923 mbuf_freem(nd->nd_mrep);
3928 * Lower level function that performs the LockU RPC.
3931 nfsrpc_locku(struct nfsrv_descript *nd, struct nfsmount *nmp,
3932 struct nfscllockowner *lp, u_int64_t off, u_int64_t len,
3933 u_int32_t type, struct ucred *cred, NFSPROC_T *p, int syscred)
3938 nfscl_reqstart(nd, NFSPROC_LOCKU, nmp, lp->nfsl_open->nfso_fh,
3939 lp->nfsl_open->nfso_fhlen, NULL, NULL);
3940 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
3941 *tl++ = txdr_unsigned(type);
3942 *tl = txdr_unsigned(lp->nfsl_seqid);
3943 if (nfstest_outofseq &&
3944 (arc4random() % nfstest_outofseq) == 0)
3945 *tl = txdr_unsigned(lp->nfsl_seqid + 1);
3947 if (NFSHASNFSV4N(nmp))
3950 *tl++ = lp->nfsl_stateid.seqid;
3951 *tl++ = lp->nfsl_stateid.other[0];
3952 *tl++ = lp->nfsl_stateid.other[1];
3953 *tl++ = lp->nfsl_stateid.other[2];
3954 txdr_hyper(off, tl);
3956 txdr_hyper(len, tl);
3958 nd->nd_flag |= ND_USEGSSNAME;
3959 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
3960 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
3961 NFSCL_INCRSEQID(lp->nfsl_seqid, nd);
3964 if (nd->nd_repstat == 0) {
3965 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3966 lp->nfsl_stateid.seqid = *tl++;
3967 lp->nfsl_stateid.other[0] = *tl++;
3968 lp->nfsl_stateid.other[1] = *tl++;
3969 lp->nfsl_stateid.other[2] = *tl;
3970 } else if (nd->nd_repstat == NFSERR_STALESTATEID)
3971 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp);
3973 mbuf_freem(nd->nd_mrep);
3978 * The actual Lock RPC.
3981 nfsrpc_lock(struct nfsrv_descript *nd, struct nfsmount *nmp, vnode_t vp,
3982 u_int8_t *nfhp, int fhlen, struct nfscllockowner *lp, int newone,
3983 int reclaim, u_int64_t off, u_int64_t len, short type, struct ucred *cred,
3984 NFSPROC_T *p, int syscred)
3988 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
3989 struct nfsclsession *tsep;
3991 nfscl_reqstart(nd, NFSPROC_LOCK, nmp, nfhp, fhlen, NULL, NULL);
3992 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
3993 if (type == F_RDLCK)
3994 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
3996 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
3997 *tl++ = txdr_unsigned(reclaim);
3998 txdr_hyper(off, tl);
4000 txdr_hyper(len, tl);
4004 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID +
4005 2 * NFSX_UNSIGNED + NFSX_HYPER);
4006 *tl++ = txdr_unsigned(lp->nfsl_open->nfso_own->nfsow_seqid);
4007 if (NFSHASNFSV4N(nmp))
4010 *tl++ = lp->nfsl_open->nfso_stateid.seqid;
4011 *tl++ = lp->nfsl_open->nfso_stateid.other[0];
4012 *tl++ = lp->nfsl_open->nfso_stateid.other[1];
4013 *tl++ = lp->nfsl_open->nfso_stateid.other[2];
4014 *tl++ = txdr_unsigned(lp->nfsl_seqid);
4015 tsep = nfsmnt_mdssession(nmp);
4016 *tl++ = tsep->nfsess_clientid.lval[0];
4017 *tl = tsep->nfsess_clientid.lval[1];
4018 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN);
4019 NFSBCOPY(nfhp, &own[NFSV4CL_LOCKNAMELEN], fhlen);
4020 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen);
4023 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
4024 if (NFSHASNFSV4N(nmp))
4027 *tl++ = lp->nfsl_stateid.seqid;
4028 *tl++ = lp->nfsl_stateid.other[0];
4029 *tl++ = lp->nfsl_stateid.other[1];
4030 *tl++ = lp->nfsl_stateid.other[2];
4031 *tl = txdr_unsigned(lp->nfsl_seqid);
4032 if (nfstest_outofseq &&
4033 (arc4random() % nfstest_outofseq) == 0)
4034 *tl = txdr_unsigned(lp->nfsl_seqid + 1);
4037 nd->nd_flag |= ND_USEGSSNAME;
4038 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
4039 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4043 NFSCL_INCRSEQID(lp->nfsl_open->nfso_own->nfsow_seqid, nd);
4044 NFSCL_INCRSEQID(lp->nfsl_seqid, nd);
4045 if (nd->nd_repstat == 0) {
4046 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
4047 lp->nfsl_stateid.seqid = *tl++;
4048 lp->nfsl_stateid.other[0] = *tl++;
4049 lp->nfsl_stateid.other[1] = *tl++;
4050 lp->nfsl_stateid.other[2] = *tl;
4051 } else if (nd->nd_repstat == NFSERR_DENIED) {
4052 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
4053 size = fxdr_unsigned(int, *(tl + 7));
4054 if (size < 0 || size > NFSV4_OPAQUELIMIT)
4057 error = nfsm_advance(nd, NFSM_RNDUP(size), -1);
4058 } else if (nd->nd_repstat == NFSERR_STALESTATEID)
4059 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp);
4061 mbuf_freem(nd->nd_mrep);
4067 * (always called with the vp for the mount point)
4070 nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp,
4071 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
4074 u_int32_t *tl = NULL;
4075 struct nfsrv_descript nfsd, *nd = &nfsd;
4076 struct nfsmount *nmp;
4077 nfsattrbit_t attrbits;
4081 nmp = VFSTONFS(vnode_mount(vp));
4082 if (NFSHASNFSV4(nmp)) {
4084 * For V4, you actually do a getattr.
4086 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
4087 NFSSTATFS_GETATTRBIT(&attrbits);
4088 (void) nfsrv_putattrbit(nd, &attrbits);
4089 nd->nd_flag |= ND_USEGSSNAME;
4090 error = nfscl_request(nd, vp, p, cred, stuff);
4093 if (nd->nd_repstat == 0) {
4094 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
4095 NULL, NULL, sbp, fsp, NULL, 0, NULL, NULL, NULL, p,
4098 nmp->nm_fsid[0] = nap->na_filesid[0];
4099 nmp->nm_fsid[1] = nap->na_filesid[1];
4100 NFSSETHASSETFSID(nmp);
4104 error = nd->nd_repstat;
4109 NFSCL_REQSTART(nd, NFSPROC_FSSTAT, vp);
4110 error = nfscl_request(nd, vp, p, cred, stuff);
4113 if (nd->nd_flag & ND_NFSV3) {
4114 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
4118 if (nd->nd_repstat) {
4119 error = nd->nd_repstat;
4122 NFSM_DISSECT(tl, u_int32_t *,
4123 NFSX_STATFS(nd->nd_flag & ND_NFSV3));
4125 if (NFSHASNFSV3(nmp)) {
4126 sbp->sf_tbytes = fxdr_hyper(tl); tl += 2;
4127 sbp->sf_fbytes = fxdr_hyper(tl); tl += 2;
4128 sbp->sf_abytes = fxdr_hyper(tl); tl += 2;
4129 sbp->sf_tfiles = fxdr_hyper(tl); tl += 2;
4130 sbp->sf_ffiles = fxdr_hyper(tl); tl += 2;
4131 sbp->sf_afiles = fxdr_hyper(tl); tl += 2;
4132 sbp->sf_invarsec = fxdr_unsigned(u_int32_t, *tl);
4133 } else if (NFSHASNFSV4(nmp) == 0) {
4134 sbp->sf_tsize = fxdr_unsigned(u_int32_t, *tl++);
4135 sbp->sf_bsize = fxdr_unsigned(u_int32_t, *tl++);
4136 sbp->sf_blocks = fxdr_unsigned(u_int32_t, *tl++);
4137 sbp->sf_bfree = fxdr_unsigned(u_int32_t, *tl++);
4138 sbp->sf_bavail = fxdr_unsigned(u_int32_t, *tl);
4141 mbuf_freem(nd->nd_mrep);
4149 nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc,
4150 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
4153 struct nfsrv_descript nfsd, *nd = &nfsd;
4154 struct nfsmount *nmp;
4156 nfsattrbit_t attrbits;
4160 nmp = VFSTONFS(vnode_mount(vp));
4161 if (NFSHASNFSV4(nmp)) {
4163 * For V4, you actually do a getattr.
4165 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
4166 NFSPATHCONF_GETATTRBIT(&attrbits);
4167 (void) nfsrv_putattrbit(nd, &attrbits);
4168 nd->nd_flag |= ND_USEGSSNAME;
4169 error = nfscl_request(nd, vp, p, cred, stuff);
4172 if (nd->nd_repstat == 0) {
4173 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
4174 pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, p,
4179 error = nd->nd_repstat;
4182 NFSCL_REQSTART(nd, NFSPROC_PATHCONF, vp);
4183 error = nfscl_request(nd, vp, p, cred, stuff);
4186 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
4187 if (nd->nd_repstat && !error)
4188 error = nd->nd_repstat;
4190 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3PATHCONF);
4191 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl++);
4192 pc->pc_namemax = fxdr_unsigned(u_int32_t, *tl++);
4193 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl++);
4194 pc->pc_chownrestricted =
4195 fxdr_unsigned(u_int32_t, *tl++);
4196 pc->pc_caseinsensitive =
4197 fxdr_unsigned(u_int32_t, *tl++);
4198 pc->pc_casepreserving = fxdr_unsigned(u_int32_t, *tl);
4202 mbuf_freem(nd->nd_mrep);
4207 * nfs version 3 fsinfo rpc call
4210 nfsrpc_fsinfo(vnode_t vp, struct nfsfsinfo *fsp, struct ucred *cred,
4211 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
4214 struct nfsrv_descript nfsd, *nd = &nfsd;
4218 NFSCL_REQSTART(nd, NFSPROC_FSINFO, vp);
4219 error = nfscl_request(nd, vp, p, cred, stuff);
4222 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
4223 if (nd->nd_repstat && !error)
4224 error = nd->nd_repstat;
4226 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3FSINFO);
4227 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *tl++);
4228 fsp->fs_rtpref = fxdr_unsigned(u_int32_t, *tl++);
4229 fsp->fs_rtmult = fxdr_unsigned(u_int32_t, *tl++);
4230 fsp->fs_wtmax = fxdr_unsigned(u_int32_t, *tl++);
4231 fsp->fs_wtpref = fxdr_unsigned(u_int32_t, *tl++);
4232 fsp->fs_wtmult = fxdr_unsigned(u_int32_t, *tl++);
4233 fsp->fs_dtpref = fxdr_unsigned(u_int32_t, *tl++);
4234 fsp->fs_maxfilesize = fxdr_hyper(tl);
4236 fxdr_nfsv3time(tl, &fsp->fs_timedelta);
4238 fsp->fs_properties = fxdr_unsigned(u_int32_t, *tl);
4241 mbuf_freem(nd->nd_mrep);
4246 * This function performs the Renew RPC.
4249 nfsrpc_renew(struct nfsclclient *clp, struct nfsclds *dsp, struct ucred *cred,
4253 struct nfsrv_descript nfsd;
4254 struct nfsrv_descript *nd = &nfsd;
4255 struct nfsmount *nmp;
4257 struct nfssockreq *nrp;
4258 struct nfsclsession *tsep;
4260 nmp = clp->nfsc_nmp;
4264 nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL, NULL);
4266 nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL,
4267 &dsp->nfsclds_sess);
4268 if (!NFSHASNFSV4N(nmp)) {
4269 /* NFSv4.1 just uses a Sequence Op and not a Renew. */
4270 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4271 tsep = nfsmnt_mdssession(nmp);
4272 *tl++ = tsep->nfsess_clientid.lval[0];
4273 *tl = tsep->nfsess_clientid.lval[1];
4277 nrp = dsp->nfsclds_sockp;
4279 /* If NULL, use the MDS socket. */
4280 nrp = &nmp->nm_sockreq;
4281 nd->nd_flag |= ND_USEGSSNAME;
4283 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
4284 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4286 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
4287 NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
4290 error = nd->nd_repstat;
4291 mbuf_freem(nd->nd_mrep);
4296 * This function performs the Releaselockowner RPC.
4299 nfsrpc_rellockown(struct nfsmount *nmp, struct nfscllockowner *lp,
4300 uint8_t *fh, int fhlen, struct ucred *cred, NFSPROC_T *p)
4302 struct nfsrv_descript nfsd, *nd = &nfsd;
4305 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
4306 struct nfsclsession *tsep;
4308 if (NFSHASNFSV4N(nmp)) {
4309 /* For NFSv4.1, do a FreeStateID. */
4310 nfscl_reqstart(nd, NFSPROC_FREESTATEID, nmp, NULL, 0, NULL,
4312 nfsm_stateidtom(nd, &lp->nfsl_stateid, NFSSTATEID_PUTSTATEID);
4314 nfscl_reqstart(nd, NFSPROC_RELEASELCKOWN, nmp, NULL, 0, NULL,
4316 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4317 tsep = nfsmnt_mdssession(nmp);
4318 *tl++ = tsep->nfsess_clientid.lval[0];
4319 *tl = tsep->nfsess_clientid.lval[1];
4320 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN);
4321 NFSBCOPY(fh, &own[NFSV4CL_LOCKNAMELEN], fhlen);
4322 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen);
4324 nd->nd_flag |= ND_USEGSSNAME;
4325 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4326 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4329 error = nd->nd_repstat;
4330 mbuf_freem(nd->nd_mrep);
4335 * This function performs the Compound to get the mount pt FH.
4338 nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred,
4342 struct nfsrv_descript nfsd;
4343 struct nfsrv_descript *nd = &nfsd;
4345 int error, cnt, len, setnil;
4348 nfscl_reqstart(nd, NFSPROC_PUTROOTFH, nmp, NULL, 0, &opcntp, NULL);
4356 while (*cp2 != '\0' && *cp2 != '/')
4363 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4364 *tl = txdr_unsigned(NFSV4OP_LOOKUP);
4365 nfsm_strtom(nd, cp, strlen(cp));
4371 } while (*cp != '\0');
4372 if (NFSHASNFSV4N(nmp))
4373 /* Has a Sequence Op done by nfscl_reqstart(). */
4374 *opcntp = txdr_unsigned(3 + cnt);
4376 *opcntp = txdr_unsigned(2 + cnt);
4377 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4378 *tl = txdr_unsigned(NFSV4OP_GETFH);
4379 nd->nd_flag |= ND_USEGSSNAME;
4380 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4381 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4384 if (nd->nd_repstat == 0) {
4385 NFSM_DISSECT(tl, u_int32_t *, (3 + 2 * cnt) * NFSX_UNSIGNED);
4386 tl += (2 + 2 * cnt);
4387 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
4389 nd->nd_repstat = NFSERR_BADXDR;
4391 nd->nd_repstat = nfsrv_mtostr(nd, nmp->nm_fh, len);
4392 if (nd->nd_repstat == 0)
4393 nmp->nm_fhsize = len;
4396 error = nd->nd_repstat;
4398 mbuf_freem(nd->nd_mrep);
4403 * This function performs the Delegreturn RPC.
4406 nfsrpc_delegreturn(struct nfscldeleg *dp, struct ucred *cred,
4407 struct nfsmount *nmp, NFSPROC_T *p, int syscred)
4410 struct nfsrv_descript nfsd;
4411 struct nfsrv_descript *nd = &nfsd;
4414 nfscl_reqstart(nd, NFSPROC_DELEGRETURN, nmp, dp->nfsdl_fh,
4415 dp->nfsdl_fhlen, NULL, NULL);
4416 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
4417 if (NFSHASNFSV4N(nmp))
4420 *tl++ = dp->nfsdl_stateid.seqid;
4421 *tl++ = dp->nfsdl_stateid.other[0];
4422 *tl++ = dp->nfsdl_stateid.other[1];
4423 *tl = dp->nfsdl_stateid.other[2];
4425 nd->nd_flag |= ND_USEGSSNAME;
4426 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4427 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4430 error = nd->nd_repstat;
4431 mbuf_freem(nd->nd_mrep);
4439 nfsrpc_getacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
4440 struct acl *aclp, void *stuff)
4442 struct nfsrv_descript nfsd, *nd = &nfsd;
4444 nfsattrbit_t attrbits;
4445 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
4447 if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp))
4448 return (EOPNOTSUPP);
4449 NFSCL_REQSTART(nd, NFSPROC_GETACL, vp);
4450 NFSZERO_ATTRBIT(&attrbits);
4451 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
4452 (void) nfsrv_putattrbit(nd, &attrbits);
4453 error = nfscl_request(nd, vp, p, cred, stuff);
4456 if (!nd->nd_repstat)
4457 error = nfsv4_loadattr(nd, vp, NULL, NULL, NULL, 0, NULL,
4458 NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, p, cred);
4460 error = nd->nd_repstat;
4461 mbuf_freem(nd->nd_mrep);
4469 nfsrpc_setacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
4470 struct acl *aclp, void *stuff)
4473 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
4475 if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp))
4476 return (EOPNOTSUPP);
4477 error = nfsrpc_setattr(vp, NULL, aclp, cred, p, NULL, NULL, stuff);
4485 nfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
4486 struct acl *aclp, nfsv4stateid_t *stateidp, void *stuff)
4488 struct nfsrv_descript nfsd, *nd = &nfsd;
4490 nfsattrbit_t attrbits;
4491 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
4493 if (!NFSHASNFSV4(nmp))
4494 return (EOPNOTSUPP);
4495 NFSCL_REQSTART(nd, NFSPROC_SETACL, vp);
4496 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
4497 NFSZERO_ATTRBIT(&attrbits);
4498 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
4499 (void) nfsv4_fillattr(nd, vnode_mount(vp), vp, aclp, NULL, NULL, 0,
4500 &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0);
4501 error = nfscl_request(nd, vp, p, cred, stuff);
4504 /* Don't care about the pre/postop attributes */
4505 mbuf_freem(nd->nd_mrep);
4506 return (nd->nd_repstat);
4510 * Do the NFSv4.1 Exchange ID.
4513 nfsrpc_exchangeid(struct nfsmount *nmp, struct nfsclclient *clp,
4514 struct nfssockreq *nrp, uint32_t exchflags, struct nfsclds **dspp,
4515 struct ucred *cred, NFSPROC_T *p)
4517 uint32_t *tl, v41flags;
4518 struct nfsrv_descript nfsd;
4519 struct nfsrv_descript *nd = &nfsd;
4520 struct nfsclds *dsp;
4521 struct timespec verstime;
4525 nfscl_reqstart(nd, NFSPROC_EXCHANGEID, nmp, NULL, 0, NULL, NULL);
4526 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4527 *tl++ = txdr_unsigned(nfsboottime.tv_sec); /* Client owner */
4528 *tl = txdr_unsigned(clp->nfsc_rev);
4529 (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen);
4531 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
4532 *tl++ = txdr_unsigned(exchflags);
4533 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE);
4535 /* Set the implementation id4 */
4536 *tl = txdr_unsigned(1);
4537 (void) nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
4538 (void) nfsm_strtom(nd, version, strlen(version));
4539 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
4540 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */
4541 verstime.tv_nsec = 0;
4542 txdr_nfsv4time(&verstime, tl);
4543 nd->nd_flag |= ND_USEGSSNAME;
4544 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
4545 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4546 NFSCL_DEBUG(1, "exchangeid err=%d reps=%d\n", error,
4547 (int)nd->nd_repstat);
4550 if (nd->nd_repstat == 0) {
4551 NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_UNSIGNED + NFSX_HYPER);
4552 len = fxdr_unsigned(int, *(tl + 7));
4553 if (len < 0 || len > NFSV4_OPAQUELIMIT) {
4554 error = NFSERR_BADXDR;
4557 dsp = malloc(sizeof(struct nfsclds) + len + 1, M_NFSCLDS,
4559 dsp->nfsclds_expire = NFSD_MONOSEC + clp->nfsc_renew;
4560 dsp->nfsclds_servownlen = len;
4561 dsp->nfsclds_sess.nfsess_clientid.lval[0] = *tl++;
4562 dsp->nfsclds_sess.nfsess_clientid.lval[1] = *tl++;
4563 dsp->nfsclds_sess.nfsess_sequenceid =
4564 fxdr_unsigned(uint32_t, *tl++);
4565 v41flags = fxdr_unsigned(uint32_t, *tl);
4566 if ((v41flags & NFSV4EXCH_USEPNFSMDS) != 0 &&
4567 NFSHASPNFSOPT(nmp)) {
4568 NFSCL_DEBUG(1, "set PNFS\n");
4570 nmp->nm_state |= NFSSTA_PNFS;
4572 dsp->nfsclds_flags |= NFSCLDS_MDS;
4574 if ((v41flags & NFSV4EXCH_USEPNFSDS) != 0)
4575 dsp->nfsclds_flags |= NFSCLDS_DS;
4577 nd->nd_repstat = nfsrv_mtostr(nd,
4578 dsp->nfsclds_serverown, len);
4579 if (nd->nd_repstat == 0) {
4580 mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF);
4581 mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession",
4583 nfscl_initsessionslots(&dsp->nfsclds_sess);
4586 free(dsp, M_NFSCLDS);
4588 error = nd->nd_repstat;
4590 mbuf_freem(nd->nd_mrep);
4595 * Do the NFSv4.1 Create Session.
4598 nfsrpc_createsession(struct nfsmount *nmp, struct nfsclsession *sep,
4599 struct nfssockreq *nrp, uint32_t sequenceid, int mds, struct ucred *cred,
4602 uint32_t crflags, *tl;
4603 struct nfsrv_descript nfsd;
4604 struct nfsrv_descript *nd = &nfsd;
4607 nfscl_reqstart(nd, NFSPROC_CREATESESSION, nmp, NULL, 0, NULL, NULL);
4608 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4609 *tl++ = sep->nfsess_clientid.lval[0];
4610 *tl++ = sep->nfsess_clientid.lval[1];
4611 *tl++ = txdr_unsigned(sequenceid);
4612 crflags = (NFSMNT_RDONLY(nmp->nm_mountp) ? 0 : NFSV4CRSESS_PERSIST);
4613 if (nfscl_enablecallb != 0 && nfs_numnfscbd > 0 && mds != 0)
4614 crflags |= NFSV4CRSESS_CONNBACKCHAN;
4615 *tl = txdr_unsigned(crflags);
4617 /* Fill in fore channel attributes. */
4618 NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4619 *tl++ = 0; /* Header pad size */
4620 *tl++ = txdr_unsigned(100000); /* Max request size */
4621 *tl++ = txdr_unsigned(100000); /* Max response size */
4622 *tl++ = txdr_unsigned(4096); /* Max response size cached */
4623 *tl++ = txdr_unsigned(20); /* Max operations */
4624 *tl++ = txdr_unsigned(64); /* Max slots */
4625 *tl = 0; /* No rdma ird */
4627 /* Fill in back channel attributes. */
4628 NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4629 *tl++ = 0; /* Header pad size */
4630 *tl++ = txdr_unsigned(10000); /* Max request size */
4631 *tl++ = txdr_unsigned(10000); /* Max response size */
4632 *tl++ = txdr_unsigned(4096); /* Max response size cached */
4633 *tl++ = txdr_unsigned(4); /* Max operations */
4634 *tl++ = txdr_unsigned(NFSV4_CBSLOTS); /* Max slots */
4635 *tl = 0; /* No rdma ird */
4637 NFSM_BUILD(tl, uint32_t *, 8 * NFSX_UNSIGNED);
4638 *tl++ = txdr_unsigned(NFS_CALLBCKPROG); /* Call back prog # */
4640 /* Allow AUTH_SYS callbacks as uid, gid == 0. */
4641 *tl++ = txdr_unsigned(1); /* Auth_sys only */
4642 *tl++ = txdr_unsigned(AUTH_SYS); /* AUTH_SYS type */
4643 *tl++ = txdr_unsigned(nfsboottime.tv_sec); /* time stamp */
4644 *tl++ = 0; /* Null machine name */
4645 *tl++ = 0; /* Uid == 0 */
4646 *tl++ = 0; /* Gid == 0 */
4647 *tl = 0; /* No additional gids */
4648 nd->nd_flag |= ND_USEGSSNAME;
4649 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, NFS_PROG,
4650 NFS_VER4, NULL, 1, NULL, NULL);
4653 if (nd->nd_repstat == 0) {
4654 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID +
4656 bcopy(tl, sep->nfsess_sessionid, NFSX_V4SESSIONID);
4657 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4658 sep->nfsess_sequenceid = fxdr_unsigned(uint32_t, *tl++);
4659 crflags = fxdr_unsigned(uint32_t, *tl);
4660 if ((crflags & NFSV4CRSESS_PERSIST) != 0 && mds != 0) {
4662 nmp->nm_state |= NFSSTA_SESSPERSIST;
4666 /* Get the fore channel slot count. */
4667 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4668 tl += 3; /* Skip the other counts. */
4669 sep->nfsess_maxcache = fxdr_unsigned(int, *tl++);
4671 sep->nfsess_foreslots = fxdr_unsigned(uint16_t, *tl++);
4672 NFSCL_DEBUG(4, "fore slots=%d\n", (int)sep->nfsess_foreslots);
4673 irdcnt = fxdr_unsigned(int, *tl);
4675 NFSM_DISSECT(tl, uint32_t *, irdcnt * NFSX_UNSIGNED);
4677 /* and the back channel slot count. */
4678 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4680 sep->nfsess_backslots = fxdr_unsigned(uint16_t, *tl);
4681 NFSCL_DEBUG(4, "back slots=%d\n", (int)sep->nfsess_backslots);
4683 error = nd->nd_repstat;
4685 mbuf_freem(nd->nd_mrep);
4690 * Do the NFSv4.1 Destroy Session.
4693 nfsrpc_destroysession(struct nfsmount *nmp, struct nfsclclient *clp,
4694 struct ucred *cred, NFSPROC_T *p)
4697 struct nfsrv_descript nfsd;
4698 struct nfsrv_descript *nd = &nfsd;
4700 struct nfsclsession *tsep;
4702 nfscl_reqstart(nd, NFSPROC_DESTROYSESSION, nmp, NULL, 0, NULL, NULL);
4703 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4704 tsep = nfsmnt_mdssession(nmp);
4705 bcopy(tsep->nfsess_sessionid, tl, NFSX_V4SESSIONID);
4706 nd->nd_flag |= ND_USEGSSNAME;
4707 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4708 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4711 error = nd->nd_repstat;
4712 mbuf_freem(nd->nd_mrep);
4717 * Do the NFSv4.1 Destroy Client.
4720 nfsrpc_destroyclient(struct nfsmount *nmp, struct nfsclclient *clp,
4721 struct ucred *cred, NFSPROC_T *p)
4724 struct nfsrv_descript nfsd;
4725 struct nfsrv_descript *nd = &nfsd;
4727 struct nfsclsession *tsep;
4729 nfscl_reqstart(nd, NFSPROC_DESTROYCLIENT, nmp, NULL, 0, NULL, NULL);
4730 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4731 tsep = nfsmnt_mdssession(nmp);
4732 *tl++ = tsep->nfsess_clientid.lval[0];
4733 *tl = tsep->nfsess_clientid.lval[1];
4734 nd->nd_flag |= ND_USEGSSNAME;
4735 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4736 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4739 error = nd->nd_repstat;
4740 mbuf_freem(nd->nd_mrep);
4745 * Do the NFSv4.1 LayoutGet.
4748 nfsrpc_layoutget(struct nfsmount *nmp, uint8_t *fhp, int fhlen, int iomode,
4749 uint64_t offset, uint64_t len, uint64_t minlen, int layoutlen,
4750 nfsv4stateid_t *stateidp, int *retonclosep, struct nfsclflayouthead *flhp,
4751 struct ucred *cred, NFSPROC_T *p, void *stuff)
4754 struct nfsrv_descript nfsd, *nd = &nfsd;
4756 struct nfsclflayout *flp, *prevflp, *tflp;
4757 int cnt, error, gotiomode, fhcnt, nfhlen, i, j;
4763 nfscl_reqstart(nd, NFSPROC_LAYOUTGET, nmp, fhp, fhlen, NULL, NULL);
4764 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
4766 *tl++ = newnfs_false; /* Don't signal availability. */
4767 *tl++ = txdr_unsigned(NFSLAYOUT_NFSV4_1_FILES);
4768 *tl++ = txdr_unsigned(iomode);
4769 txdr_hyper(offset, tl);
4771 txdr_hyper(len, tl);
4773 txdr_hyper(minlen, tl);
4775 *tl++ = txdr_unsigned(stateidp->seqid);
4776 NFSCL_DEBUG(4, "layget seq=%d\n", (int)stateidp->seqid);
4777 *tl++ = stateidp->other[0];
4778 *tl++ = stateidp->other[1];
4779 *tl++ = stateidp->other[2];
4780 *tl = txdr_unsigned(layoutlen);
4781 nd->nd_flag |= ND_USEGSSNAME;
4782 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4783 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4786 if (nd->nd_repstat == 0) {
4787 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_STATEID);
4792 stateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
4793 NFSCL_DEBUG(4, "retoncls=%d stseq=%d\n", *retonclosep,
4794 (int)stateidp->seqid);
4795 stateidp->other[0] = *tl++;
4796 stateidp->other[1] = *tl++;
4797 stateidp->other[2] = *tl++;
4798 cnt = fxdr_unsigned(int, *tl);
4799 NFSCL_DEBUG(4, "layg cnt=%d\n", cnt);
4800 if (cnt <= 0 || cnt > 10000) {
4801 /* Don't accept more than 10000 layouts in reply. */
4802 error = NFSERR_BADXDR;
4805 for (i = 0; i < cnt; i++) {
4806 /* Dissect all the way to the file handle cnt. */
4807 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_HYPER +
4808 6 * NFSX_UNSIGNED + NFSX_V4DEVICEID);
4809 fhcnt = fxdr_unsigned(int, *(tl + 11 +
4810 NFSX_V4DEVICEID / NFSX_UNSIGNED));
4811 NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt);
4812 if (fhcnt < 0 || fhcnt > 100) {
4813 /* Don't accept more than 100 file handles. */
4814 error = NFSERR_BADXDR;
4818 flp = malloc(sizeof(*flp) + (fhcnt - 1) *
4819 sizeof(struct nfsfh *),
4820 M_NFSFLAYOUT, M_WAITOK);
4822 flp = malloc(sizeof(*flp),
4823 M_NFSFLAYOUT, M_WAITOK);
4824 flp->nfsfl_flags = 0;
4825 flp->nfsfl_fhcnt = 0;
4826 flp->nfsfl_devp = NULL;
4827 flp->nfsfl_off = fxdr_hyper(tl); tl += 2;
4828 retlen = fxdr_hyper(tl); tl += 2;
4829 if (flp->nfsfl_off + retlen < flp->nfsfl_off)
4830 flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off;
4832 flp->nfsfl_end = flp->nfsfl_off + retlen;
4833 flp->nfsfl_iomode = fxdr_unsigned(int, *tl++);
4834 if (gotiomode == -1)
4835 gotiomode = flp->nfsfl_iomode;
4836 NFSCL_DEBUG(4, "layg reqiom=%d retiom=%d\n", iomode,
4837 (int)flp->nfsfl_iomode);
4838 if (fxdr_unsigned(int, *tl++) !=
4839 NFSLAYOUT_NFSV4_1_FILES) {
4840 printf("NFSv4.1: got non-files layout\n");
4841 error = NFSERR_BADXDR;
4844 NFSBCOPY(++tl, flp->nfsfl_dev, NFSX_V4DEVICEID);
4845 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
4846 flp->nfsfl_util = fxdr_unsigned(uint32_t, *tl++);
4847 NFSCL_DEBUG(4, "flutil=0x%x\n", flp->nfsfl_util);
4848 flp->nfsfl_stripe1 = fxdr_unsigned(uint32_t, *tl++);
4849 flp->nfsfl_patoff = fxdr_hyper(tl); tl += 2;
4850 if (fxdr_unsigned(int, *tl) != fhcnt) {
4851 printf("EEK! bad fhcnt\n");
4852 error = NFSERR_BADXDR;
4855 for (j = 0; j < fhcnt; j++) {
4856 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4857 nfhlen = fxdr_unsigned(int, *tl);
4858 if (nfhlen <= 0 || nfhlen > NFSX_V4FHMAX) {
4859 error = NFSERR_BADXDR;
4862 nfhp = malloc(sizeof(*nfhp) + nfhlen - 1,
4864 flp->nfsfl_fh[j] = nfhp;
4866 nfhp->nfh_len = nfhlen;
4867 NFSM_DISSECT(cp, uint8_t *, NFSM_RNDUP(nfhlen));
4868 NFSBCOPY(cp, nfhp->nfh_fh, nfhlen);
4870 if (flp->nfsfl_iomode == gotiomode) {
4871 /* Keep the list in increasing offset order. */
4872 tflp = LIST_FIRST(flhp);
4874 while (tflp != NULL &&
4875 tflp->nfsfl_off < flp->nfsfl_off) {
4877 tflp = LIST_NEXT(tflp, nfsfl_list);
4879 if (prevflp == NULL)
4880 LIST_INSERT_HEAD(flhp, flp, nfsfl_list);
4882 LIST_INSERT_AFTER(prevflp, flp,
4885 printf("nfscl_layoutget(): got wrong iomode\n");
4886 nfscl_freeflayout(flp);
4891 if (nd->nd_repstat != 0 && error == 0)
4892 error = nd->nd_repstat;
4894 if (error != 0 && flp != NULL)
4895 nfscl_freeflayout(flp);
4896 mbuf_freem(nd->nd_mrep);
4901 * Do the NFSv4.1 Get Device Info.
4904 nfsrpc_getdeviceinfo(struct nfsmount *nmp, uint8_t *deviceid, int layouttype,
4905 uint32_t *notifybitsp, struct nfscldevinfo **ndip, struct ucred *cred,
4909 struct nfsrv_descript nfsd;
4910 struct nfsrv_descript *nd = &nfsd;
4911 struct sockaddr_storage ss;
4912 struct nfsclds *dsp = NULL, **dspp;
4913 struct nfscldevinfo *ndi;
4914 int addrcnt, bitcnt, error, i, isudp, j, pos, safilled, stripecnt;
4915 uint8_t stripeindex;
4919 nfscl_reqstart(nd, NFSPROC_GETDEVICEINFO, nmp, NULL, 0, NULL, NULL);
4920 NFSM_BUILD(tl, uint32_t *, NFSX_V4DEVICEID + 3 * NFSX_UNSIGNED);
4921 NFSBCOPY(deviceid, tl, NFSX_V4DEVICEID);
4922 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
4923 *tl++ = txdr_unsigned(layouttype);
4924 *tl++ = txdr_unsigned(100000);
4925 if (notifybitsp != NULL && *notifybitsp != 0) {
4926 *tl = txdr_unsigned(1); /* One word of bits. */
4927 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4928 *tl = txdr_unsigned(*notifybitsp);
4930 *tl = txdr_unsigned(0);
4931 nd->nd_flag |= ND_USEGSSNAME;
4932 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4933 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4936 if (nd->nd_repstat == 0) {
4937 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED);
4938 if (layouttype != fxdr_unsigned(int, *tl++))
4939 printf("EEK! devinfo layout type not same!\n");
4940 stripecnt = fxdr_unsigned(int, *++tl);
4941 NFSCL_DEBUG(4, "stripecnt=%d\n", stripecnt);
4942 if (stripecnt < 1 || stripecnt > 4096) {
4943 printf("NFS devinfo stripecnt %d: out of range\n",
4945 error = NFSERR_BADXDR;
4948 NFSM_DISSECT(tl, uint32_t *, (stripecnt + 1) * NFSX_UNSIGNED);
4949 addrcnt = fxdr_unsigned(int, *(tl + stripecnt));
4950 NFSCL_DEBUG(4, "addrcnt=%d\n", addrcnt);
4951 if (addrcnt < 1 || addrcnt > 128) {
4952 printf("NFS devinfo addrcnt %d: out of range\n",
4954 error = NFSERR_BADXDR;
4959 * Now we know how many stripe indices and addresses, so
4960 * we can allocate the structure the correct size.
4962 i = (stripecnt * sizeof(uint8_t)) / sizeof(struct nfsclds *)
4964 NFSCL_DEBUG(4, "stripeindices=%d\n", i);
4965 ndi = malloc(sizeof(*ndi) + (addrcnt + i) *
4966 sizeof(struct nfsclds *), M_NFSDEVINFO, M_WAITOK | M_ZERO);
4967 NFSBCOPY(deviceid, ndi->nfsdi_deviceid, NFSX_V4DEVICEID);
4968 ndi->nfsdi_refcnt = 0;
4969 ndi->nfsdi_stripecnt = stripecnt;
4970 ndi->nfsdi_addrcnt = addrcnt;
4971 /* Fill in the stripe indices. */
4972 for (i = 0; i < stripecnt; i++) {
4973 stripeindex = fxdr_unsigned(uint8_t, *tl++);
4974 NFSCL_DEBUG(4, "stripeind=%d\n", stripeindex);
4975 if (stripeindex >= addrcnt) {
4976 printf("NFS devinfo stripeindex %d: too big\n",
4978 error = NFSERR_BADXDR;
4981 nfsfldi_setstripeindex(ndi, i, stripeindex);
4984 /* Now, dissect the server address(es). */
4986 for (i = 0; i < addrcnt; i++) {
4987 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4988 cnt = fxdr_unsigned(uint32_t, *tl);
4990 printf("NFS devinfo 0 len addrlist\n");
4991 error = NFSERR_BADXDR;
4994 dspp = nfsfldi_addr(ndi, i);
4995 pos = arc4random() % cnt; /* Choose one. */
4997 for (j = 0; j < cnt; j++) {
4998 error = nfsv4_getipaddr(nd, &ss, &isudp);
4999 if (error != 0 && error != EPERM) {
5000 error = NFSERR_BADXDR;
5003 if (error == 0 && isudp == 0) {
5006 * - use "pos" entry if it is of the
5007 * same af_family or none of them
5008 * is of the same af_family
5010 * - use the first one of the same
5013 if ((safilled == 0 && ss.ss_family ==
5014 nmp->nm_nam->sa_family) ||
5016 (safilled == 0 || ss.ss_family ==
5017 nmp->nm_nam->sa_family)) ||
5018 (safilled == 1 && ss.ss_family ==
5019 nmp->nm_nam->sa_family)) {
5020 error = nfsrpc_fillsa(nmp, &ss,
5025 nmp->nm_nam->sa_family)
5037 /* And the notify bits. */
5038 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5039 if (safilled != 0) {
5040 bitcnt = fxdr_unsigned(int, *tl);
5042 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5043 if (notifybitsp != NULL)
5045 fxdr_unsigned(uint32_t, *tl);
5051 if (nd->nd_repstat != 0)
5052 error = nd->nd_repstat;
5054 if (error != 0 && ndi != NULL)
5055 nfscl_freedevinfo(ndi);
5056 mbuf_freem(nd->nd_mrep);
5061 * Do the NFSv4.1 LayoutCommit.
5064 nfsrpc_layoutcommit(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim,
5065 uint64_t off, uint64_t len, uint64_t lastbyte, nfsv4stateid_t *stateidp,
5066 int layouttype, int layoutupdatecnt, uint8_t *layp, struct ucred *cred,
5067 NFSPROC_T *p, void *stuff)
5070 struct nfsrv_descript nfsd, *nd = &nfsd;
5071 int error, outcnt, i;
5074 nfscl_reqstart(nd, NFSPROC_LAYOUTCOMMIT, nmp, fh, fhlen, NULL, NULL);
5075 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
5077 txdr_hyper(off, tl);
5079 txdr_hyper(len, tl);
5082 *tl++ = newnfs_true;
5084 *tl++ = newnfs_false;
5085 *tl++ = txdr_unsigned(stateidp->seqid);
5086 *tl++ = stateidp->other[0];
5087 *tl++ = stateidp->other[1];
5088 *tl++ = stateidp->other[2];
5089 *tl++ = newnfs_true;
5092 else if (lastbyte >= (off + len))
5093 lastbyte = off + len - 1;
5094 txdr_hyper(lastbyte, tl);
5096 *tl++ = newnfs_false;
5097 *tl++ = txdr_unsigned(layouttype);
5098 *tl = txdr_unsigned(layoutupdatecnt);
5099 if (layoutupdatecnt > 0) {
5100 KASSERT(layouttype != NFSLAYOUT_NFSV4_1_FILES,
5101 ("Must be nil for Files Layout"));
5102 outcnt = NFSM_RNDUP(layoutupdatecnt);
5103 NFSM_BUILD(cp, uint8_t *, outcnt);
5104 NFSBCOPY(layp, cp, layoutupdatecnt);
5105 cp += layoutupdatecnt;
5106 for (i = 0; i < (outcnt - layoutupdatecnt); i++)
5109 nd->nd_flag |= ND_USEGSSNAME;
5110 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5111 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5114 error = nd->nd_repstat;
5115 mbuf_freem(nd->nd_mrep);
5120 * Do the NFSv4.1 LayoutReturn.
5123 nfsrpc_layoutreturn(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim,
5124 int layouttype, uint32_t iomode, int layoutreturn, uint64_t offset,
5125 uint64_t len, nfsv4stateid_t *stateidp, int layoutcnt, uint32_t *layp,
5126 struct ucred *cred, NFSPROC_T *p, void *stuff)
5129 struct nfsrv_descript nfsd, *nd = &nfsd;
5130 int error, outcnt, i;
5133 nfscl_reqstart(nd, NFSPROC_LAYOUTRETURN, nmp, fh, fhlen, NULL, NULL);
5134 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED);
5136 *tl++ = newnfs_true;
5138 *tl++ = newnfs_false;
5139 *tl++ = txdr_unsigned(layouttype);
5140 *tl++ = txdr_unsigned(iomode);
5141 *tl = txdr_unsigned(layoutreturn);
5142 if (layoutreturn == NFSLAYOUTRETURN_FILE) {
5143 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
5145 txdr_hyper(offset, tl);
5147 txdr_hyper(len, tl);
5149 NFSCL_DEBUG(4, "layoutret stseq=%d\n", (int)stateidp->seqid);
5150 *tl++ = txdr_unsigned(stateidp->seqid);
5151 *tl++ = stateidp->other[0];
5152 *tl++ = stateidp->other[1];
5153 *tl++ = stateidp->other[2];
5154 *tl = txdr_unsigned(layoutcnt);
5155 if (layoutcnt > 0) {
5156 outcnt = NFSM_RNDUP(layoutcnt);
5157 NFSM_BUILD(cp, uint8_t *, outcnt);
5158 NFSBCOPY(layp, cp, layoutcnt);
5160 for (i = 0; i < (outcnt - layoutcnt); i++)
5164 nd->nd_flag |= ND_USEGSSNAME;
5165 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5166 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5169 if (nd->nd_repstat == 0) {
5170 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5172 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
5173 stateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
5174 stateidp->other[0] = *tl++;
5175 stateidp->other[1] = *tl++;
5176 stateidp->other[2] = *tl;
5179 error = nd->nd_repstat;
5181 mbuf_freem(nd->nd_mrep);
5186 * Acquire a layout and devinfo, if possible. The caller must have acquired
5187 * a reference count on the nfsclclient structure before calling this.
5188 * Return the layout in lypp with a reference count on it, if successful.
5191 nfsrpc_getlayout(struct nfsmount *nmp, vnode_t vp, struct nfsfh *nfhp,
5192 int iomode, uint32_t *notifybitsp, nfsv4stateid_t *stateidp, uint64_t off,
5193 struct nfscllayout **lypp, struct ucred *cred, NFSPROC_T *p)
5195 struct nfscllayout *lyp;
5196 struct nfsclflayout *flp, *tflp;
5197 struct nfscldevinfo *dip;
5198 struct nfsclflayouthead flh;
5199 int error = 0, islocked, layoutlen, recalled, retonclose;
5200 nfsv4stateid_t stateid;
5201 struct nfsclsession *tsep;
5205 * If lyp is returned non-NULL, there will be a refcnt (shared lock)
5206 * on it, iff flp != NULL or a lock (exclusive lock) on it iff
5209 lyp = nfscl_getlayout(nmp->nm_clp, nfhp->nfh_fh, nfhp->nfh_len,
5210 off, &flp, &recalled);
5212 if (lyp == NULL || flp == NULL) {
5216 tsep = nfsmnt_mdssession(nmp);
5217 layoutlen = tsep->nfsess_maxcache -
5218 (NFSX_STATEID + 3 * NFSX_UNSIGNED);
5221 stateid.other[0] = stateidp->other[0];
5222 stateid.other[1] = stateidp->other[1];
5223 stateid.other[2] = stateidp->other[2];
5224 error = nfsrpc_layoutget(nmp, nfhp->nfh_fh,
5225 nfhp->nfh_len, iomode, (uint64_t)0, INT64_MAX,
5226 (uint64_t)0, layoutlen, &stateid, &retonclose,
5227 &flh, cred, p, NULL);
5230 stateid.seqid = lyp->nfsly_stateid.seqid;
5231 stateid.other[0] = lyp->nfsly_stateid.other[0];
5232 stateid.other[1] = lyp->nfsly_stateid.other[1];
5233 stateid.other[2] = lyp->nfsly_stateid.other[2];
5234 error = nfsrpc_layoutget(nmp, nfhp->nfh_fh,
5235 nfhp->nfh_len, iomode, off, INT64_MAX,
5236 (uint64_t)0, layoutlen, &stateid, &retonclose,
5237 &flh, cred, p, NULL);
5240 LIST_FOREACH(tflp, &flh, nfsfl_list) {
5241 error = nfscl_adddevinfo(nmp, NULL, tflp);
5243 error = nfsrpc_getdeviceinfo(nmp,
5245 NFSLAYOUT_NFSV4_1_FILES,
5246 notifybitsp, &dip, cred, p);
5249 error = nfscl_adddevinfo(nmp, dip,
5253 "getlayout: cannot add\n");
5258 * nfscl_layout() always returns with the nfsly_lock
5259 * set to a refcnt (shared lock).
5261 error = nfscl_layout(nmp, vp, nfhp->nfh_fh,
5262 nfhp->nfh_len, &stateid, retonclose, &flh, &lyp,
5266 } else if (islocked != 0)
5267 nfsv4_unlock(&lyp->nfsly_lock, 0);
5274 * Do a TCP connection plus exchange id and create session.
5275 * If successful, a "struct nfsclds" is linked into the list for the
5276 * mount point and a pointer to it is returned.
5279 nfsrpc_fillsa(struct nfsmount *nmp, struct sockaddr_storage *ssp,
5280 struct nfsclds **dspp, NFSPROC_T *p)
5282 struct sockaddr_in *msad, *sad, *ssd;
5283 struct sockaddr_in6 *msad6, *sad6, *ssd6;
5284 struct nfsclclient *clp;
5285 struct nfssockreq *nrp;
5286 struct nfsclds *dsp, *tdsp;
5288 enum nfsclds_state retv;
5289 uint32_t sequenceid;
5291 KASSERT(nmp->nm_sockreq.nr_cred != NULL,
5292 ("nfsrpc_fillsa: NULL nr_cred"));
5298 if (ssp->ss_family == AF_INET) {
5299 ssd = (struct sockaddr_in *)ssp;
5303 * Check to see if we already have a session for this
5304 * address that is usable for a DS.
5305 * Note that the MDS's address is in a different place
5306 * than the sessions already acquired for DS's.
5308 msad = (struct sockaddr_in *)nmp->nm_sockreq.nr_nam;
5309 tdsp = TAILQ_FIRST(&nmp->nm_sess);
5310 while (tdsp != NULL) {
5311 if (msad != NULL && msad->sin_family == AF_INET &&
5312 ssd->sin_addr.s_addr == msad->sin_addr.s_addr &&
5313 ssd->sin_port == msad->sin_port &&
5314 (tdsp->nfsclds_flags & NFSCLDS_DS) != 0 &&
5315 tdsp->nfsclds_sess.nfsess_defunct == 0) {
5318 NFSCL_DEBUG(4, "fnd same addr\n");
5321 tdsp = TAILQ_NEXT(tdsp, nfsclds_list);
5322 if (tdsp != NULL && tdsp->nfsclds_sockp != NULL)
5323 msad = (struct sockaddr_in *)
5324 tdsp->nfsclds_sockp->nr_nam;
5330 /* No IP address match, so look for new/trunked one. */
5331 sad = malloc(sizeof(*sad), M_SONAME, M_WAITOK | M_ZERO);
5332 sad->sin_len = sizeof(*sad);
5333 sad->sin_family = AF_INET;
5334 sad->sin_port = ssd->sin_port;
5335 sad->sin_addr.s_addr = ssd->sin_addr.s_addr;
5336 nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO);
5337 nrp->nr_nam = (struct sockaddr *)sad;
5338 } else if (ssp->ss_family == AF_INET6) {
5339 ssd6 = (struct sockaddr_in6 *)ssp;
5343 * Check to see if we already have a session for this
5344 * address that is usable for a DS.
5345 * Note that the MDS's address is in a different place
5346 * than the sessions already acquired for DS's.
5348 msad6 = (struct sockaddr_in6 *)nmp->nm_sockreq.nr_nam;
5349 tdsp = TAILQ_FIRST(&nmp->nm_sess);
5350 while (tdsp != NULL) {
5351 if (msad6 != NULL && msad6->sin6_family == AF_INET6 &&
5352 IN6_ARE_ADDR_EQUAL(&ssd6->sin6_addr,
5353 &msad6->sin6_addr) &&
5354 ssd6->sin6_port == msad6->sin6_port &&
5355 (tdsp->nfsclds_flags & NFSCLDS_DS) != 0 &&
5356 tdsp->nfsclds_sess.nfsess_defunct == 0) {
5361 tdsp = TAILQ_NEXT(tdsp, nfsclds_list);
5362 if (tdsp != NULL && tdsp->nfsclds_sockp != NULL)
5363 msad6 = (struct sockaddr_in6 *)
5364 tdsp->nfsclds_sockp->nr_nam;
5370 /* No IP address match, so look for new/trunked one. */
5371 sad6 = malloc(sizeof(*sad6), M_SONAME, M_WAITOK | M_ZERO);
5372 sad6->sin6_len = sizeof(*sad6);
5373 sad6->sin6_family = AF_INET6;
5374 sad6->sin6_port = ssd6->sin6_port;
5375 NFSBCOPY(&ssd6->sin6_addr, &sad6->sin6_addr,
5376 sizeof(struct in6_addr));
5377 nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO);
5378 nrp->nr_nam = (struct sockaddr *)sad6;
5382 nrp->nr_sotype = SOCK_STREAM;
5383 mtx_init(&nrp->nr_mtx, "nfssock", NULL, MTX_DEF);
5384 nrp->nr_prog = NFS_PROG;
5385 nrp->nr_vers = NFS_VER4;
5388 * Use the credentials that were used for the mount, which are
5389 * in nmp->nm_sockreq.nr_cred for newnfs_connect() etc.
5390 * Ref. counting the credentials with crhold() is probably not
5391 * necessary, since nm_sockreq.nr_cred won't be crfree()'d until
5392 * unmount, but I did it anyhow.
5394 nrp->nr_cred = crhold(nmp->nm_sockreq.nr_cred);
5395 error = newnfs_connect(nmp, nrp, NULL, p, 0);
5396 NFSCL_DEBUG(3, "DS connect=%d\n", error);
5398 /* Now, do the exchangeid and create session. */
5400 error = nfsrpc_exchangeid(nmp, clp, nrp, NFSV4EXCH_USEPNFSDS,
5401 &dsp, nrp->nr_cred, p);
5402 NFSCL_DEBUG(3, "DS exchangeid=%d\n", error);
5404 dsp->nfsclds_sockp = nrp;
5406 retv = nfscl_getsameserver(nmp, dsp, &tdsp);
5407 NFSCL_DEBUG(3, "getsame ret=%d\n", retv);
5408 if (retv == NFSDSP_USETHISSESSION) {
5411 * If there is already a session for this server,
5414 (void)newnfs_disconnect(nrp);
5415 nfscl_freenfsclds(dsp);
5419 if (retv == NFSDSP_SEQTHISSESSION)
5420 sequenceid = tdsp->nfsclds_sess.nfsess_sequenceid;
5422 sequenceid = dsp->nfsclds_sess.nfsess_sequenceid;
5424 error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess,
5425 nrp, sequenceid, 0, nrp->nr_cred, p);
5426 NFSCL_DEBUG(3, "DS createsess=%d\n", error);
5428 NFSFREECRED(nrp->nr_cred);
5429 NFSFREEMUTEX(&nrp->nr_mtx);
5430 free(nrp->nr_nam, M_SONAME);
5431 free(nrp, M_NFSSOCKREQ);
5434 NFSCL_DEBUG(3, "add DS session\n");
5436 * Put it at the end of the list. That way the list
5437 * is ordered by when the entry was added. This matters
5438 * since the one done first is the one that should be
5439 * used for sequencid'ing any subsequent create sessions.
5442 TAILQ_INSERT_TAIL(&nmp->nm_sess, dsp, nfsclds_list);
5445 } else if (dsp != NULL)
5446 nfscl_freenfsclds(dsp);
5451 * Do the NFSv4.1 Reclaim Complete.
5454 nfsrpc_reclaimcomplete(struct nfsmount *nmp, struct ucred *cred, NFSPROC_T *p)
5457 struct nfsrv_descript nfsd;
5458 struct nfsrv_descript *nd = &nfsd;
5461 nfscl_reqstart(nd, NFSPROC_RECLAIMCOMPL, nmp, NULL, 0, NULL, NULL);
5462 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5464 nd->nd_flag |= ND_USEGSSNAME;
5465 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5466 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5469 error = nd->nd_repstat;
5470 mbuf_freem(nd->nd_mrep);
5475 * Initialize the slot tables for a session.
5478 nfscl_initsessionslots(struct nfsclsession *sep)
5482 for (i = 0; i < NFSV4_CBSLOTS; i++) {
5483 if (sep->nfsess_cbslots[i].nfssl_reply != NULL)
5484 m_freem(sep->nfsess_cbslots[i].nfssl_reply);
5485 NFSBZERO(&sep->nfsess_cbslots[i], sizeof(struct nfsslot));
5487 for (i = 0; i < 64; i++)
5488 sep->nfsess_slotseq[i] = 0;
5489 sep->nfsess_slots = 0;
5493 * Called to try and do an I/O operation via an NFSv4.1 Data Server (DS).
5496 nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
5497 uint32_t rwaccess, struct ucred *cred, NFSPROC_T *p)
5499 struct nfsnode *np = VTONFS(vp);
5500 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
5501 struct nfscllayout *layp;
5502 struct nfscldevinfo *dip;
5503 struct nfsclflayout *rflp;
5504 nfsv4stateid_t stateid;
5505 struct ucred *newcred;
5506 uint64_t lastbyte, len, off, oresid, xfer;
5507 int eof, error, iolaymode, recalled;
5510 if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || nfs_numnfscbd == 0 ||
5511 (np->n_flag & NNOLAYOUT) != 0)
5513 /* Now, get a reference cnt on the clientid for this mount. */
5514 if (nfscl_getref(nmp) == 0)
5517 /* Find an appropriate stateid. */
5518 newcred = NFSNEWCRED(cred);
5519 error = nfscl_getstateid(vp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len,
5520 rwaccess, 1, newcred, p, &stateid, &lckp);
5522 NFSFREECRED(newcred);
5526 /* Search for a layout for this file. */
5527 off = uiop->uio_offset;
5528 layp = nfscl_getlayout(nmp->nm_clp, np->n_fhp->nfh_fh,
5529 np->n_fhp->nfh_len, off, &rflp, &recalled);
5530 if (layp == NULL || rflp == NULL) {
5531 if (recalled != 0) {
5532 NFSFREECRED(newcred);
5537 nfscl_rellayout(layp, (rflp == NULL) ? 1 : 0);
5540 /* Try and get a Layout, if it is supported. */
5541 if (rwaccess == NFSV4OPEN_ACCESSWRITE ||
5542 (np->n_flag & NWRITEOPENED) != 0)
5543 iolaymode = NFSLAYOUTIOMODE_RW;
5545 iolaymode = NFSLAYOUTIOMODE_READ;
5546 error = nfsrpc_getlayout(nmp, vp, np->n_fhp, iolaymode,
5547 NULL, &stateid, off, &layp, newcred, p);
5550 np->n_flag |= NNOLAYOUT;
5553 nfscl_lockderef(lckp);
5554 NFSFREECRED(newcred);
5556 nfscl_rellayout(layp, 0);
5563 * Loop around finding a layout that works for the first part of
5564 * this I/O operation, and then call the function that actually
5568 len = (uint64_t)uiop->uio_resid;
5569 while (len > 0 && error == 0 && eof == 0) {
5570 off = uiop->uio_offset;
5571 error = nfscl_findlayoutforio(layp, off, rwaccess, &rflp);
5573 oresid = xfer = (uint64_t)uiop->uio_resid;
5574 if (xfer > (rflp->nfsfl_end - rflp->nfsfl_off))
5575 xfer = rflp->nfsfl_end - rflp->nfsfl_off;
5576 dip = nfscl_getdevinfo(nmp->nm_clp, rflp->nfsfl_dev,
5579 error = nfscl_doflayoutio(vp, uiop, iomode,
5580 must_commit, &eof, &stateid, rwaccess, dip,
5581 layp, rflp, off, xfer, newcred, p);
5582 nfscl_reldevinfo(dip);
5583 lastbyte = off + xfer - 1;
5586 if (lastbyte > layp->nfsly_lastbyte)
5587 layp->nfsly_lastbyte = lastbyte;
5593 len -= (oresid - (uint64_t)uiop->uio_resid);
5597 nfscl_lockderef(lckp);
5598 NFSFREECRED(newcred);
5599 nfscl_rellayout(layp, 0);
5605 * Find a file layout that will handle the first bytes of the requested
5606 * range and return the information from it needed to to the I/O operation.
5609 nfscl_findlayoutforio(struct nfscllayout *lyp, uint64_t off, uint32_t rwaccess,
5610 struct nfsclflayout **retflpp)
5612 struct nfsclflayout *flp, *nflp, *rflp;
5617 /* For reading, do the Read list first and then the Write list. */
5619 if (rw == NFSV4OPEN_ACCESSREAD)
5620 flp = LIST_FIRST(&lyp->nfsly_flayread);
5622 flp = LIST_FIRST(&lyp->nfsly_flayrw);
5623 while (flp != NULL) {
5624 nflp = LIST_NEXT(flp, nfsfl_list);
5625 if (flp->nfsfl_off > off)
5627 if (flp->nfsfl_end > off &&
5628 (rflp == NULL || rflp->nfsfl_end < flp->nfsfl_end))
5632 if (rw == NFSV4OPEN_ACCESSREAD)
5633 rw = NFSV4OPEN_ACCESSWRITE;
5638 /* This one covers the most bytes starting at off. */
5646 * Do I/O using an NFSv4.1 file layout.
5649 nfscl_doflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
5650 int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp,
5651 struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off,
5652 uint64_t len, struct ucred *cred, NFSPROC_T *p)
5654 uint64_t io_off, rel_off, stripe_unit_size, transfer, xfer;
5655 int commit_thru_mds, error = 0, stripe_index, stripe_pos;
5658 struct nfsclds **dspp;
5661 rel_off = off - flp->nfsfl_patoff;
5662 stripe_unit_size = (flp->nfsfl_util >> 6) & 0x3ffffff;
5663 stripe_pos = (rel_off / stripe_unit_size + flp->nfsfl_stripe1) %
5664 dp->nfsdi_stripecnt;
5665 transfer = stripe_unit_size - (rel_off % stripe_unit_size);
5667 /* Loop around, doing I/O for each stripe unit. */
5668 while (len > 0 && error == 0) {
5669 stripe_index = nfsfldi_stripeindex(dp, stripe_pos);
5670 dspp = nfsfldi_addr(dp, stripe_index);
5675 if ((flp->nfsfl_util & NFSFLAYUTIL_DENSE) != 0) {
5677 if (stripe_pos >= flp->nfsfl_fhcnt)
5679 fhp = flp->nfsfl_fh[stripe_pos];
5680 io_off = (rel_off / (stripe_unit_size *
5681 dp->nfsdi_stripecnt)) * stripe_unit_size +
5682 rel_off % stripe_unit_size;
5684 /* Sparse layout. */
5685 if (flp->nfsfl_fhcnt > 1) {
5686 if (stripe_index >= flp->nfsfl_fhcnt)
5688 fhp = flp->nfsfl_fh[stripe_index];
5689 } else if (flp->nfsfl_fhcnt == 1)
5690 fhp = flp->nfsfl_fh[0];
5695 if ((flp->nfsfl_util & NFSFLAYUTIL_COMMIT_THRU_MDS) != 0)
5696 commit_thru_mds = 1;
5698 commit_thru_mds = 0;
5699 if (rwflag == FREAD)
5700 error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp,
5701 io_off, xfer, fhp, cred, p);
5703 error = nfsrpc_writeds(vp, uiop, iomode, must_commit,
5704 stateidp, *dspp, io_off, xfer, fhp, commit_thru_mds,
5708 lyp->nfsly_flags |= NFSLY_WRITTEN;
5713 transfer = stripe_unit_size;
5714 stripe_pos = (stripe_pos + 1) % dp->nfsdi_stripecnt;
5723 * The actual read RPC done to a DS.
5726 nfsrpc_readds(vnode_t vp, struct uio *uiop, nfsv4stateid_t *stateidp, int *eofp,
5727 struct nfsclds *dsp, uint64_t io_off, int len, struct nfsfh *fhp,
5728 struct ucred *cred, NFSPROC_T *p)
5732 struct nfsrv_descript nfsd;
5733 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
5734 struct nfsrv_descript *nd = &nfsd;
5735 struct nfssockreq *nrp;
5738 nfscl_reqstart(nd, NFSPROC_READDS, nmp, fhp->nfh_fh, fhp->nfh_len,
5739 NULL, &dsp->nfsclds_sess);
5740 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO);
5741 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED * 3);
5742 txdr_hyper(io_off, tl);
5743 *(tl + 2) = txdr_unsigned(len);
5744 nrp = dsp->nfsclds_sockp;
5746 /* If NULL, use the MDS socket. */
5747 nrp = &nmp->nm_sockreq;
5748 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
5749 NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
5752 if (nd->nd_repstat != 0) {
5753 error = nd->nd_repstat;
5756 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5757 *eofp = fxdr_unsigned(int, *tl);
5758 NFSM_STRSIZ(retlen, len);
5759 error = nfsm_mbufuio(nd, uiop, retlen);
5761 if (nd->nd_mrep != NULL)
5762 mbuf_freem(nd->nd_mrep);
5767 * The actual write RPC done to a DS.
5770 nfsrpc_writeds(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
5771 nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len,
5772 struct nfsfh *fhp, int commit_thru_mds, struct ucred *cred, NFSPROC_T *p)
5775 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
5776 int error, rlen, commit, committed = NFSWRITE_FILESYNC;
5778 struct nfsrv_descript nfsd;
5779 struct nfsrv_descript *nd = &nfsd;
5780 struct nfssockreq *nrp;
5782 KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1"));
5784 nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh, fhp->nfh_len,
5785 NULL, &dsp->nfsclds_sess);
5786 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO);
5787 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
5788 txdr_hyper(io_off, tl);
5790 *tl++ = txdr_unsigned(*iomode);
5791 *tl = txdr_unsigned(len);
5792 nfsm_uiombuf(nd, uiop, len);
5793 nrp = dsp->nfsclds_sockp;
5795 /* If NULL, use the MDS socket. */
5796 nrp = &nmp->nm_sockreq;
5797 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
5798 NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
5801 if (nd->nd_repstat != 0) {
5803 * In case the rpc gets retried, roll
5804 * the uio fileds changed by nfsm_uiombuf()
5807 uiop->uio_offset -= len;
5808 uio_uio_resid_add(uiop, len);
5809 uio_iov_base_add(uiop, -len);
5810 uio_iov_len_add(uiop, len);
5811 error = nd->nd_repstat;
5813 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF);
5814 rlen = fxdr_unsigned(int, *tl++);
5818 } else if (rlen < len) {
5819 backup = len - rlen;
5820 uio_iov_base_add(uiop, -(backup));
5821 uio_iov_len_add(uiop, backup);
5822 uiop->uio_offset -= backup;
5823 uio_uio_resid_add(uiop, backup);
5826 commit = fxdr_unsigned(int, *tl++);
5829 * Return the lowest committment level
5830 * obtained by any of the RPCs.
5832 if (committed == NFSWRITE_FILESYNC)
5834 else if (committed == NFSWRITE_DATASYNC &&
5835 commit == NFSWRITE_UNSTABLE)
5837 if (commit_thru_mds != 0) {
5839 if (!NFSHASWRITEVERF(nmp)) {
5840 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
5841 NFSSETWRITEVERF(nmp);
5842 } else if (NFSBCMP(tl, nmp->nm_verf, NFSX_VERF)) {
5844 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
5849 if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) {
5850 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
5851 dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF;
5852 } else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) {
5854 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
5860 if (nd->nd_mrep != NULL)
5861 mbuf_freem(nd->nd_mrep);
5862 *iomode = committed;
5863 if (nd->nd_repstat != 0 && error == 0)
5864 error = nd->nd_repstat;
5869 * Free up the nfsclds structure.
5872 nfscl_freenfsclds(struct nfsclds *dsp)
5878 if (dsp->nfsclds_sockp != NULL) {
5879 NFSFREECRED(dsp->nfsclds_sockp->nr_cred);
5880 NFSFREEMUTEX(&dsp->nfsclds_sockp->nr_mtx);
5881 free(dsp->nfsclds_sockp->nr_nam, M_SONAME);
5882 free(dsp->nfsclds_sockp, M_NFSSOCKREQ);
5884 NFSFREEMUTEX(&dsp->nfsclds_mtx);
5885 NFSFREEMUTEX(&dsp->nfsclds_sess.nfsess_mtx);
5886 for (i = 0; i < NFSV4_CBSLOTS; i++) {
5887 if (dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply != NULL)
5889 dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply);
5891 free(dsp, M_NFSCLDS);
5894 static enum nfsclds_state
5895 nfscl_getsameserver(struct nfsmount *nmp, struct nfsclds *newdsp,
5896 struct nfsclds **retdspp)
5898 struct nfsclds *dsp, *cur_dsp;
5901 * Search the list of nfsclds structures for one with the same
5905 TAILQ_FOREACH(dsp, &nmp->nm_sess, nfsclds_list) {
5906 if (dsp->nfsclds_servownlen == newdsp->nfsclds_servownlen &&
5907 dsp->nfsclds_servownlen != 0 &&
5908 !NFSBCMP(dsp->nfsclds_serverown, newdsp->nfsclds_serverown,
5909 dsp->nfsclds_servownlen) &&
5910 dsp->nfsclds_sess.nfsess_defunct == 0) {
5911 NFSCL_DEBUG(4, "fnd same fdsp=%p dsp=%p flg=0x%x\n",
5912 TAILQ_FIRST(&nmp->nm_sess), dsp,
5913 dsp->nfsclds_flags);
5914 /* Server major id matches. */
5915 if ((dsp->nfsclds_flags & NFSCLDS_DS) != 0) {
5917 return (NFSDSP_USETHISSESSION);
5921 * Note the first match, so it can be used for
5922 * sequence'ing new sessions.
5924 if (cur_dsp == NULL)
5928 if (cur_dsp != NULL) {
5930 return (NFSDSP_SEQTHISSESSION);
5932 return (NFSDSP_NOTFOUND);
5937 * NFS commit rpc to a DS.
5940 nfsrpc_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp,
5941 struct nfsfh *fhp, struct ucred *cred, NFSPROC_T *p, void *stuff)
5944 struct nfsrv_descript nfsd, *nd = &nfsd;
5945 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
5946 struct nfssockreq *nrp;
5949 nfscl_reqstart(nd, NFSPROC_COMMITDS, nmp, fhp->nfh_fh, fhp->nfh_len,
5950 NULL, &dsp->nfsclds_sess);
5951 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
5952 txdr_hyper(offset, tl);
5954 *tl = txdr_unsigned(cnt);
5955 nrp = dsp->nfsclds_sockp;
5957 /* If NULL, use the MDS socket. */
5958 nrp = &nmp->nm_sockreq;
5959 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
5960 NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
5963 if (nd->nd_repstat == 0) {
5964 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
5966 if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) {
5967 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
5968 error = NFSERR_STALEWRITEVERF;
5973 if (error == 0 && nd->nd_repstat != 0)
5974 error = nd->nd_repstat;
5975 mbuf_freem(nd->nd_mrep);