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 * 3. 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 offsetof(struct dirent, d_name)
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, int, struct ucred *,
119 static int nfsrpc_readds(vnode_t, struct uio *, nfsv4stateid_t *, int *,
120 struct nfsclds *, uint64_t, int, struct nfsfh *, struct ucred *,
122 static int nfsrpc_writeds(vnode_t, struct uio *, int *, int *,
123 nfsv4stateid_t *, struct nfsclds *, uint64_t, int,
124 struct nfsfh *, int, struct ucred *, NFSPROC_T *);
125 static enum nfsclds_state nfscl_getsameserver(struct nfsmount *,
126 struct nfsclds *, struct nfsclds **);
127 static int nfsrpc_commitds(vnode_t, uint64_t, int, struct nfsclds *,
128 struct nfsfh *, struct ucred *, NFSPROC_T *);
129 static void nfsrv_setuplayoutget(struct nfsrv_descript *, int, uint64_t,
130 uint64_t, uint64_t, nfsv4stateid_t *, int, int);
131 static int nfsrv_parselayoutget(struct nfsrv_descript *, nfsv4stateid_t *,
132 int *, struct nfsclflayouthead *);
133 static int nfsrpc_getopenlayout(struct nfsmount *, vnode_t, u_int8_t *,
134 int, uint8_t *, int, uint32_t, struct nfsclopen *, uint8_t *, int,
135 struct nfscldeleg **, struct ucred *, NFSPROC_T *);
136 static int nfsrpc_getcreatelayout(vnode_t, char *, int, struct vattr *,
137 nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **,
138 struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *,
139 struct nfsfh **, int *, int *, void *, int *);
140 static int nfsrpc_openlayoutrpc(struct nfsmount *, vnode_t, u_int8_t *,
141 int, uint8_t *, int, uint32_t, struct nfsclopen *, uint8_t *, int,
142 struct nfscldeleg **, nfsv4stateid_t *, int, int, int *,
143 struct nfsclflayouthead *, int *, struct ucred *, NFSPROC_T *);
144 static int nfsrpc_createlayout(vnode_t, char *, int, struct vattr *,
145 nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **,
146 struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *,
147 struct nfsfh **, int *, int *, void *, int *, nfsv4stateid_t *,
148 int, int, int *, struct nfsclflayouthead *, int *);
149 static int nfsrpc_layoutgetres(struct nfsmount *, vnode_t, uint8_t *,
150 int, nfsv4stateid_t *, int, uint32_t *, struct nfscllayout **,
151 struct nfsclflayouthead *, int, int *, struct ucred *, NFSPROC_T *);
154 * nfs null call from vfs.
157 nfsrpc_null(vnode_t vp, struct ucred *cred, NFSPROC_T *p)
160 struct nfsrv_descript nfsd, *nd = &nfsd;
162 NFSCL_REQSTART(nd, NFSPROC_NULL, vp);
163 error = nfscl_request(nd, vp, p, cred, NULL);
164 if (nd->nd_repstat && !error)
165 error = nd->nd_repstat;
166 mbuf_freem(nd->nd_mrep);
172 * For nfs version 3 and 4, use the access rpc to check accessibility. If file
173 * modes are changed on the server, accesses might still fail later.
176 nfsrpc_access(vnode_t vp, int acmode, struct ucred *cred,
177 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp)
180 u_int32_t mode, rmode;
183 mode = NFSACCESS_READ;
186 if (vnode_vtype(vp) == VDIR) {
188 mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND |
191 mode |= NFSACCESS_LOOKUP;
194 mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND);
196 mode |= NFSACCESS_EXECUTE;
200 * Now, just call nfsrpc_accessrpc() to do the actual RPC.
202 error = nfsrpc_accessrpc(vp, mode, cred, p, nap, attrflagp, &rmode,
206 * The NFS V3 spec does not clarify whether or not
207 * the returned access bits can be a superset of
208 * the ones requested, so...
210 if (!error && (rmode & mode) != mode)
216 * The actual rpc, separated out for Darwin.
219 nfsrpc_accessrpc(vnode_t vp, u_int32_t mode, struct ucred *cred,
220 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, u_int32_t *rmodep,
224 u_int32_t supported, rmode;
226 struct nfsrv_descript nfsd, *nd = &nfsd;
227 nfsattrbit_t attrbits;
231 NFSCL_REQSTART(nd, NFSPROC_ACCESS, vp);
232 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
233 *tl = txdr_unsigned(mode);
234 if (nd->nd_flag & ND_NFSV4) {
236 * And do a Getattr op.
238 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
239 *tl = txdr_unsigned(NFSV4OP_GETATTR);
240 NFSGETATTR_ATTRBIT(&attrbits);
241 (void) nfsrv_putattrbit(nd, &attrbits);
243 error = nfscl_request(nd, vp, p, cred, stuff);
246 if (nd->nd_flag & ND_NFSV3) {
247 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
251 if (!nd->nd_repstat) {
252 if (nd->nd_flag & ND_NFSV4) {
253 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
254 supported = fxdr_unsigned(u_int32_t, *tl++);
256 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
258 rmode = fxdr_unsigned(u_int32_t, *tl);
259 if (nd->nd_flag & ND_NFSV4)
260 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
263 * It's not obvious what should be done about
264 * unsupported access modes. For now, be paranoid
265 * and clear the unsupported ones.
270 error = nd->nd_repstat;
272 mbuf_freem(nd->nd_mrep);
280 nfsrpc_open(vnode_t vp, int amode, struct ucred *cred, NFSPROC_T *p)
282 struct nfsclopen *op;
283 struct nfscldeleg *dp;
285 struct nfsnode *np = VTONFS(vp);
286 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
287 u_int32_t mode, clidrev;
288 int ret, newone, error, expireret = 0, retrycnt;
291 * For NFSv4, Open Ops are only done on Regular Files.
293 if (vnode_vtype(vp) != VREG)
297 mode |= NFSV4OPEN_ACCESSREAD;
299 mode |= NFSV4OPEN_ACCESSWRITE;
304 { char name[100]; int namel;
305 namel = (np->n_v4->n4_namelen < 100) ? np->n_v4->n4_namelen : 99;
306 bcopy(NFS4NODENAME(np->n_v4), name, namel);
308 printf("rpcopen p=0x%x name=%s",p->p_pid,name);
309 if (nfhp->nfh_len > 0) printf(" fh=0x%x\n",nfhp->nfh_fh[12]);
310 else printf(" fhl=0\n");
315 error = nfscl_open(vp, nfhp->nfh_fh, nfhp->nfh_len, mode, 1,
316 cred, p, NULL, &op, &newone, &ret, 1);
320 if (nmp->nm_clp != NULL)
321 clidrev = nmp->nm_clp->nfsc_clientidrev;
324 if (ret == NFSCLOPEN_DOOPEN) {
325 if (np->n_v4 != NULL) {
327 * For the first attempt, try and get a layout, if
328 * pNFS is enabled for the mount.
330 if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 ||
331 nfs_numnfscbd == 0 ||
332 (np->n_flag & NNOLAYOUT) != 0 || retrycnt > 0)
333 error = nfsrpc_openrpc(nmp, vp,
335 np->n_v4->n4_fhlen, np->n_fhp->nfh_fh,
336 np->n_fhp->nfh_len, mode, op,
337 NFS4NODENAME(np->n_v4),
338 np->n_v4->n4_namelen,
339 &dp, 0, 0x0, cred, p, 0, 0);
341 error = nfsrpc_getopenlayout(nmp, vp,
343 np->n_v4->n4_fhlen, np->n_fhp->nfh_fh,
344 np->n_fhp->nfh_len, mode, op,
345 NFS4NODENAME(np->n_v4),
346 np->n_v4->n4_namelen, &dp, cred, p);
349 OSBitAndAtomic((int32_t)~NDELEGMOD, (UInt32 *)&np->n_flag);
352 np->n_flag &= ~NDELEGMOD;
354 * Invalidate the attribute cache, so that
355 * attributes that pre-date the issue of a
356 * delegation are not cached, since the
357 * cached attributes will remain valid while
358 * the delegation is held.
360 NFSINVALATTRCACHE(np);
363 (void) nfscl_deleg(nmp->nm_mountp,
364 op->nfso_own->nfsow_clp,
365 nfhp->nfh_fh, nfhp->nfh_len, cred, p, &dp);
370 newnfs_copyincred(cred, &op->nfso_cred);
371 } else if (ret == NFSCLOPEN_SETCRED)
373 * This is a new local open on a delegation. It needs
374 * to have credentials so that an open can be done
375 * against the server during recovery.
377 newnfs_copyincred(cred, &op->nfso_cred);
380 * nfso_opencnt is the count of how many VOP_OPEN()s have
381 * been done on this Open successfully and a VOP_CLOSE()
382 * is expected for each of these.
383 * If error is non-zero, don't increment it, since the Open
384 * hasn't succeeded yet.
388 nfscl_openrelease(nmp, op, error, newone);
389 if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
390 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
391 error == NFSERR_BADSESSION) {
392 (void) nfs_catnap(PZERO, error, "nfs_open");
393 } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID)
395 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
398 } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
399 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
400 error == NFSERR_BADSESSION ||
401 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
402 expireret == 0 && clidrev != 0 && retrycnt < 4));
403 if (error && retrycnt >= 4)
409 * the actual open rpc
412 nfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen,
413 u_int8_t *newfhp, int newfhlen, u_int32_t mode, struct nfsclopen *op,
414 u_int8_t *name, int namelen, struct nfscldeleg **dpp,
415 int reclaim, u_int32_t delegtype, struct ucred *cred, NFSPROC_T *p,
416 int syscred, int recursed)
419 struct nfsrv_descript nfsd, *nd = &nfsd;
420 struct nfscldeleg *dp, *ndp = NULL;
421 struct nfsvattr nfsva;
422 u_int32_t rflags, deleg;
423 nfsattrbit_t attrbits;
424 int error, ret, acesize, limitby;
425 struct nfsclsession *tsep;
429 nfscl_reqstart(nd, NFSPROC_OPEN, nmp, nfhp, fhlen, NULL, NULL);
430 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
431 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
432 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
433 *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
434 tsep = nfsmnt_mdssession(nmp);
435 *tl++ = tsep->nfsess_clientid.lval[0];
436 *tl = tsep->nfsess_clientid.lval[1];
437 (void) nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN);
438 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
439 *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE);
441 *tl = txdr_unsigned(NFSV4OPEN_CLAIMPREVIOUS);
442 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
443 *tl = txdr_unsigned(delegtype);
446 *tl = txdr_unsigned(NFSV4OPEN_CLAIMDELEGATECUR);
447 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
448 if (NFSHASNFSV4N(nmp))
451 *tl++ = dp->nfsdl_stateid.seqid;
452 *tl++ = dp->nfsdl_stateid.other[0];
453 *tl++ = dp->nfsdl_stateid.other[1];
454 *tl = dp->nfsdl_stateid.other[2];
456 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
458 (void) nfsm_strtom(nd, name, namelen);
460 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
461 *tl = txdr_unsigned(NFSV4OP_GETATTR);
462 NFSZERO_ATTRBIT(&attrbits);
463 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
464 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY);
465 (void) nfsrv_putattrbit(nd, &attrbits);
467 nd->nd_flag |= ND_USEGSSNAME;
468 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
469 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
472 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
473 if (!nd->nd_repstat) {
474 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
476 op->nfso_stateid.seqid = *tl++;
477 op->nfso_stateid.other[0] = *tl++;
478 op->nfso_stateid.other[1] = *tl++;
479 op->nfso_stateid.other[2] = *tl;
480 rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
481 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
484 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
485 deleg = fxdr_unsigned(u_int32_t, *tl);
486 if (deleg == NFSV4OPEN_DELEGATEREAD ||
487 deleg == NFSV4OPEN_DELEGATEWRITE) {
488 if (!(op->nfso_own->nfsow_clp->nfsc_flags &
489 NFSCLFLAGS_FIRSTDELEG))
490 op->nfso_own->nfsow_clp->nfsc_flags |=
491 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
492 MALLOC(ndp, struct nfscldeleg *,
493 sizeof (struct nfscldeleg) + newfhlen,
494 M_NFSCLDELEG, M_WAITOK);
495 LIST_INIT(&ndp->nfsdl_owner);
496 LIST_INIT(&ndp->nfsdl_lock);
497 ndp->nfsdl_clp = op->nfso_own->nfsow_clp;
498 ndp->nfsdl_fhlen = newfhlen;
499 NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen);
500 newnfs_copyincred(cred, &ndp->nfsdl_cred);
501 nfscl_lockinit(&ndp->nfsdl_rwlock);
502 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
504 ndp->nfsdl_stateid.seqid = *tl++;
505 ndp->nfsdl_stateid.other[0] = *tl++;
506 ndp->nfsdl_stateid.other[1] = *tl++;
507 ndp->nfsdl_stateid.other[2] = *tl++;
508 ret = fxdr_unsigned(int, *tl);
509 if (deleg == NFSV4OPEN_DELEGATEWRITE) {
510 ndp->nfsdl_flags = NFSCLDL_WRITE;
512 * Indicates how much the file can grow.
514 NFSM_DISSECT(tl, u_int32_t *,
516 limitby = fxdr_unsigned(int, *tl++);
518 case NFSV4OPEN_LIMITSIZE:
519 ndp->nfsdl_sizelimit = fxdr_hyper(tl);
521 case NFSV4OPEN_LIMITBLOCKS:
522 ndp->nfsdl_sizelimit =
523 fxdr_unsigned(u_int64_t, *tl++);
524 ndp->nfsdl_sizelimit *=
525 fxdr_unsigned(u_int64_t, *tl);
528 error = NFSERR_BADXDR;
532 ndp->nfsdl_flags = NFSCLDL_READ;
535 ndp->nfsdl_flags |= NFSCLDL_RECALL;
536 error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, &ret,
540 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
541 error = NFSERR_BADXDR;
544 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
545 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
546 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
547 NULL, NULL, NULL, p, cred);
551 ndp->nfsdl_change = nfsva.na_filerev;
552 ndp->nfsdl_modtime = nfsva.na_mtime;
553 ndp->nfsdl_flags |= NFSCLDL_MODTIMESET;
555 if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM)) {
557 ret = nfsrpc_openconfirm(vp, newfhp, newfhlen, op,
559 if (ret == NFSERR_DELAY)
560 (void) nfs_catnap(PZERO, ret, "nfs_open");
561 } while (ret == NFSERR_DELAY);
564 if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) ||
565 nfscl_assumeposixlocks)
566 op->nfso_posixlock = 1;
568 op->nfso_posixlock = 0;
571 * If the server is handing out delegations, but we didn't
572 * get one because an OpenConfirm was required, try the
573 * Open again, to get a delegation. This is a harmless no-op,
574 * from a server's point of view.
576 if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM) &&
577 (op->nfso_own->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG)
578 && !error && dp == NULL && ndp == NULL && !recursed) {
580 ret = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp,
581 newfhlen, mode, op, name, namelen, &ndp, 0, 0x0,
582 cred, p, syscred, 1);
583 if (ret == NFSERR_DELAY)
584 (void) nfs_catnap(PZERO, ret, "nfs_open2");
585 } while (ret == NFSERR_DELAY);
588 FREE((caddr_t)ndp, M_NFSCLDELEG);
591 if (ret == NFSERR_STALECLIENTID ||
592 ret == NFSERR_STALEDONTRECOVER ||
593 ret == NFSERR_BADSESSION)
598 if (nd->nd_repstat != 0 && error == 0)
599 error = nd->nd_repstat;
600 if (error == NFSERR_STALECLIENTID)
601 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
605 else if (ndp != NULL)
606 FREE((caddr_t)ndp, M_NFSCLDELEG);
607 mbuf_freem(nd->nd_mrep);
615 nfsrpc_opendowngrade(vnode_t vp, u_int32_t mode, struct nfsclopen *op,
616 struct ucred *cred, NFSPROC_T *p)
619 struct nfsrv_descript nfsd, *nd = &nfsd;
622 NFSCL_REQSTART(nd, NFSPROC_OPENDOWNGRADE, vp);
623 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
624 if (NFSHASNFSV4N(VFSTONFS(vnode_mount(vp))))
627 *tl++ = op->nfso_stateid.seqid;
628 *tl++ = op->nfso_stateid.other[0];
629 *tl++ = op->nfso_stateid.other[1];
630 *tl++ = op->nfso_stateid.other[2];
631 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
632 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
633 *tl = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
634 error = nfscl_request(nd, vp, p, cred, NULL);
637 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
638 if (!nd->nd_repstat) {
639 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
640 op->nfso_stateid.seqid = *tl++;
641 op->nfso_stateid.other[0] = *tl++;
642 op->nfso_stateid.other[1] = *tl++;
643 op->nfso_stateid.other[2] = *tl;
645 if (nd->nd_repstat && error == 0)
646 error = nd->nd_repstat;
647 if (error == NFSERR_STALESTATEID)
648 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
650 mbuf_freem(nd->nd_mrep);
655 * V4 Close operation.
658 nfsrpc_close(vnode_t vp, int doclose, NFSPROC_T *p)
660 struct nfsclclient *clp;
663 if (vnode_vtype(vp) != VREG)
666 error = nfscl_doclose(vp, &clp, p);
668 error = nfscl_getclose(vp, &clp);
672 nfscl_clientrelease(clp);
680 nfsrpc_doclose(struct nfsmount *nmp, struct nfsclopen *op, NFSPROC_T *p)
682 struct nfsrv_descript nfsd, *nd = &nfsd;
683 struct nfscllockowner *lp, *nlp;
684 struct nfscllock *lop, *nlop;
686 u_int64_t off = 0, len = 0;
687 u_int32_t type = NFSV4LOCKT_READ;
688 int error, do_unlock, trycnt;
690 tcred = newnfs_getcred();
691 newnfs_copycred(&op->nfso_cred, tcred);
693 * (Theoretically this could be done in the same
694 * compound as the close, but having multiple
695 * sequenced Ops in the same compound might be
696 * too scary for some servers.)
698 if (op->nfso_posixlock) {
701 type = NFSV4LOCKT_READ;
705 * Since this function is only called from VOP_INACTIVE(), no
706 * other thread will be manipulating this Open. As such, the
707 * lock lists are not being changed by other threads, so it should
708 * be safe to do this without locking.
710 LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) {
712 LIST_FOREACH_SAFE(lop, &lp->nfsl_lock, nfslo_list, nlop) {
713 if (op->nfso_posixlock == 0) {
714 off = lop->nfslo_first;
715 len = lop->nfslo_end - lop->nfslo_first;
716 if (lop->nfslo_type == F_WRLCK)
717 type = NFSV4LOCKT_WRITE;
719 type = NFSV4LOCKT_READ;
724 error = nfsrpc_locku(nd, nmp, lp, off,
725 len, type, tcred, p, 0);
726 if ((nd->nd_repstat == NFSERR_GRACE ||
727 nd->nd_repstat == NFSERR_DELAY) &&
729 (void) nfs_catnap(PZERO,
732 } while ((nd->nd_repstat == NFSERR_GRACE ||
733 nd->nd_repstat == NFSERR_DELAY) &&
734 error == 0 && trycnt++ < 5);
735 if (op->nfso_posixlock)
738 nfscl_freelock(lop, 0);
741 * Do a ReleaseLockOwner.
742 * The lock owner name nfsl_owner may be used by other opens for
743 * other files but the lock_owner4 name that nfsrpc_rellockown()
744 * puts on the wire has the file handle for this file appended
745 * to it, so it can be done now.
747 (void)nfsrpc_rellockown(nmp, lp, lp->nfsl_open->nfso_fh,
748 lp->nfsl_open->nfso_fhlen, tcred, p);
752 * There could be other Opens for different files on the same
753 * OpenOwner, so locking is required.
756 nfscl_lockexcl(&op->nfso_own->nfsow_rwlock, NFSCLSTATEMUTEXPTR);
759 error = nfscl_tryclose(op, tcred, nmp, p);
760 if (error == NFSERR_GRACE)
761 (void) nfs_catnap(PZERO, error, "nfs_close");
762 } while (error == NFSERR_GRACE);
764 nfscl_lockunlock(&op->nfso_own->nfsow_rwlock);
766 LIST_FOREACH_SAFE(lp, &op->nfso_lock, nfsl_list, nlp)
767 nfscl_freelockowner(lp, 0);
768 nfscl_freeopen(op, 0);
774 * The actual Close RPC.
777 nfsrpc_closerpc(struct nfsrv_descript *nd, struct nfsmount *nmp,
778 struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p,
784 nfscl_reqstart(nd, NFSPROC_CLOSE, nmp, op->nfso_fh,
785 op->nfso_fhlen, NULL, NULL);
786 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
787 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
788 if (NFSHASNFSV4N(nmp))
791 *tl++ = op->nfso_stateid.seqid;
792 *tl++ = op->nfso_stateid.other[0];
793 *tl++ = op->nfso_stateid.other[1];
794 *tl = op->nfso_stateid.other[2];
796 nd->nd_flag |= ND_USEGSSNAME;
797 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
798 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
801 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
802 if (nd->nd_repstat == 0)
803 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
804 error = nd->nd_repstat;
805 if (error == NFSERR_STALESTATEID)
806 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
808 mbuf_freem(nd->nd_mrep);
813 * V4 Open Confirm RPC.
816 nfsrpc_openconfirm(vnode_t vp, u_int8_t *nfhp, int fhlen,
817 struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p)
820 struct nfsrv_descript nfsd, *nd = &nfsd;
821 struct nfsmount *nmp;
824 nmp = VFSTONFS(vnode_mount(vp));
825 if (NFSHASNFSV4N(nmp))
826 return (0); /* No confirmation for NFSv4.1. */
827 nfscl_reqstart(nd, NFSPROC_OPENCONFIRM, nmp, nfhp, fhlen, NULL, NULL);
828 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
829 *tl++ = op->nfso_stateid.seqid;
830 *tl++ = op->nfso_stateid.other[0];
831 *tl++ = op->nfso_stateid.other[1];
832 *tl++ = op->nfso_stateid.other[2];
833 *tl = txdr_unsigned(op->nfso_own->nfsow_seqid);
834 error = nfscl_request(nd, vp, p, cred, NULL);
837 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
838 if (!nd->nd_repstat) {
839 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
840 op->nfso_stateid.seqid = *tl++;
841 op->nfso_stateid.other[0] = *tl++;
842 op->nfso_stateid.other[1] = *tl++;
843 op->nfso_stateid.other[2] = *tl;
845 error = nd->nd_repstat;
846 if (error == NFSERR_STALESTATEID)
847 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
849 mbuf_freem(nd->nd_mrep);
854 * Do the setclientid and setclientid confirm RPCs. Called from nfs_statfs()
855 * when a mount has just occurred and when the server replies NFSERR_EXPIRED.
858 nfsrpc_setclient(struct nfsmount *nmp, struct nfsclclient *clp, int reclaim,
859 struct ucred *cred, NFSPROC_T *p)
862 struct nfsrv_descript nfsd;
863 struct nfsrv_descript *nd = &nfsd;
864 nfsattrbit_t attrbits;
865 u_int8_t *cp = NULL, *cp2, addr[INET6_ADDRSTRLEN + 9];
867 int error, isinet6 = 0, callblen;
870 static u_int32_t rev = 0;
873 struct nfsclsession *tsep;
875 if (nfsboottime.tv_sec == 0)
876 NFSSETBOOTTIME(nfsboottime);
877 clp->nfsc_rev = rev++;
878 if (NFSHASNFSV4N(nmp)) {
880 * Either there was no previous session or the
881 * previous session has failed, so...
882 * do an ExchangeID followed by the CreateSession.
884 error = nfsrpc_exchangeid(nmp, clp, &nmp->nm_sockreq,
885 NFSV4EXCH_USEPNFSMDS | NFSV4EXCH_USENONPNFS, &dsp, cred, p);
886 NFSCL_DEBUG(1, "aft exch=%d\n", error);
888 error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess,
890 dsp->nfsclds_sess.nfsess_sequenceid, 1, cred, p);
894 * The old sessions cannot be safely free'd
895 * here, since they may still be used by
899 if (TAILQ_FIRST(&nmp->nm_sess) != NULL)
900 tsep = NFSMNT_MDSSESSION(nmp);
901 TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp,
904 * Wake up RPCs waiting for a slot on the
905 * old session. These will then fail with
906 * NFSERR_BADSESSION and be retried with the
907 * new session by nfsv4_setsequence().
908 * Also wakeup() processes waiting for the
912 wakeup(&tsep->nfsess_slots);
913 wakeup(&nmp->nm_sess);
916 nfscl_freenfsclds(dsp);
917 NFSCL_DEBUG(1, "aft createsess=%d\n", error);
918 if (error == 0 && reclaim == 0) {
919 error = nfsrpc_reclaimcomplete(nmp, cred, p);
920 NFSCL_DEBUG(1, "aft reclaimcomp=%d\n", error);
921 if (error == NFSERR_COMPLETEALREADY ||
922 error == NFSERR_NOTSUPP)
923 /* Ignore this error. */
930 * Allocate a single session structure for NFSv4.0, because some of
931 * the fields are used by NFSv4.0 although it doesn't do a session.
933 dsp = malloc(sizeof(struct nfsclds), M_NFSCLDS, M_WAITOK | M_ZERO);
934 mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF);
935 mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", NULL, MTX_DEF);
937 TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp, nfsclds_list);
938 tsep = NFSMNT_MDSSESSION(nmp);
941 nfscl_reqstart(nd, NFSPROC_SETCLIENTID, nmp, NULL, 0, NULL, NULL);
942 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
943 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
944 *tl = txdr_unsigned(clp->nfsc_rev);
945 (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen);
948 * set up the callback address
950 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
951 *tl = txdr_unsigned(NFS_CALLBCKPROG);
952 callblen = strlen(nfsv4_callbackaddr);
954 cp = nfscl_getmyip(nmp, &a6, &isinet6);
955 if (nfscl_enablecallb && nfs_numnfscbd > 0 &&
956 (callblen > 0 || cp != NULL)) {
957 port = htons(nfsv4_cbport);
958 cp2 = (u_int8_t *)&port;
961 strchr(nfsv4_callbackaddr, ':')) || isinet6) {
962 char ip6buf[INET6_ADDRSTRLEN], *ip6add;
964 (void) nfsm_strtom(nd, "tcp6", 4);
966 ip6_sprintf(ip6buf, (struct in6_addr *)cp);
969 ip6add = nfsv4_callbackaddr;
971 snprintf(addr, INET6_ADDRSTRLEN + 9, "%s.%d.%d",
972 ip6add, cp2[0], cp2[1]);
976 (void) nfsm_strtom(nd, "tcp", 3);
978 snprintf(addr, INET6_ADDRSTRLEN + 9,
979 "%d.%d.%d.%d.%d.%d", cp[0], cp[1],
980 cp[2], cp[3], cp2[0], cp2[1]);
982 snprintf(addr, INET6_ADDRSTRLEN + 9,
983 "%s.%d.%d", nfsv4_callbackaddr,
986 (void) nfsm_strtom(nd, addr, strlen(addr));
988 (void) nfsm_strtom(nd, "tcp", 3);
989 (void) nfsm_strtom(nd, "0.0.0.0.0.0", 11);
991 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
992 *tl = txdr_unsigned(clp->nfsc_cbident);
993 nd->nd_flag |= ND_USEGSSNAME;
994 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
995 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
998 if (nd->nd_repstat == 0) {
999 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1000 tsep->nfsess_clientid.lval[0] = *tl++;
1001 tsep->nfsess_clientid.lval[1] = *tl++;
1002 confirm.lval[0] = *tl++;
1003 confirm.lval[1] = *tl;
1004 mbuf_freem(nd->nd_mrep);
1010 nfscl_reqstart(nd, NFSPROC_SETCLIENTIDCFRM, nmp, NULL, 0, NULL,
1012 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1013 *tl++ = tsep->nfsess_clientid.lval[0];
1014 *tl++ = tsep->nfsess_clientid.lval[1];
1015 *tl++ = confirm.lval[0];
1016 *tl = confirm.lval[1];
1017 nd->nd_flag |= ND_USEGSSNAME;
1018 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p,
1019 cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
1022 mbuf_freem(nd->nd_mrep);
1024 if (nd->nd_repstat == 0) {
1025 nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, nmp->nm_fh,
1026 nmp->nm_fhsize, NULL, NULL);
1027 NFSZERO_ATTRBIT(&attrbits);
1028 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME);
1029 (void) nfsrv_putattrbit(nd, &attrbits);
1030 nd->nd_flag |= ND_USEGSSNAME;
1031 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p,
1032 cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
1035 if (nd->nd_repstat == 0) {
1036 error = nfsv4_loadattr(nd, NULL, NULL, NULL, NULL, 0, NULL,
1037 NULL, NULL, NULL, NULL, 0, NULL, &lease, NULL, p, cred);
1040 clp->nfsc_renew = NFSCL_RENEW(lease);
1041 clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew;
1042 clp->nfsc_clientidrev++;
1043 if (clp->nfsc_clientidrev == 0)
1044 clp->nfsc_clientidrev++;
1048 error = nd->nd_repstat;
1050 mbuf_freem(nd->nd_mrep);
1058 nfsrpc_getattr(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
1059 struct nfsvattr *nap, void *stuff)
1061 struct nfsrv_descript nfsd, *nd = &nfsd;
1063 nfsattrbit_t attrbits;
1065 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
1066 if (nd->nd_flag & ND_NFSV4) {
1067 NFSGETATTR_ATTRBIT(&attrbits);
1068 (void) nfsrv_putattrbit(nd, &attrbits);
1070 error = nfscl_request(nd, vp, p, cred, stuff);
1073 if (!nd->nd_repstat)
1074 error = nfsm_loadattr(nd, nap);
1076 error = nd->nd_repstat;
1077 mbuf_freem(nd->nd_mrep);
1082 * nfs getattr call with non-vnode arguemnts.
1085 nfsrpc_getattrnovp(struct nfsmount *nmp, u_int8_t *fhp, int fhlen, int syscred,
1086 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, u_int64_t *xidp,
1089 struct nfsrv_descript nfsd, *nd = &nfsd;
1090 int error, vers = NFS_VER2;
1091 nfsattrbit_t attrbits;
1093 nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, fhp, fhlen, NULL, NULL);
1094 if (nd->nd_flag & ND_NFSV4) {
1096 NFSGETATTR_ATTRBIT(&attrbits);
1097 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME);
1098 (void) nfsrv_putattrbit(nd, &attrbits);
1099 } else if (nd->nd_flag & ND_NFSV3) {
1103 nd->nd_flag |= ND_USEGSSNAME;
1104 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
1105 NFS_PROG, vers, NULL, 1, xidp, NULL);
1108 if (nd->nd_repstat == 0) {
1109 if ((nd->nd_flag & ND_NFSV4) != 0)
1110 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
1111 NULL, NULL, NULL, NULL, NULL, 0, NULL, leasep, NULL,
1114 error = nfsm_loadattr(nd, nap);
1116 error = nd->nd_repstat;
1117 mbuf_freem(nd->nd_mrep);
1122 * Do an nfs setattr operation.
1125 nfsrpc_setattr(vnode_t vp, struct vattr *vap, NFSACL_T *aclp,
1126 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *rnap, int *attrflagp,
1129 int error, expireret = 0, openerr, retrycnt;
1130 u_int32_t clidrev = 0, mode;
1131 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1133 nfsv4stateid_t stateid;
1136 if (nmp->nm_clp != NULL)
1137 clidrev = nmp->nm_clp->nfsc_clientidrev;
1138 if (vap != NULL && NFSATTRISSET(u_quad_t, vap, va_size))
1139 mode = NFSV4OPEN_ACCESSWRITE;
1141 mode = NFSV4OPEN_ACCESSREAD;
1146 if (NFSHASNFSV4(nmp)) {
1147 nfhp = VTONFS(vp)->n_fhp;
1148 error = nfscl_getstateid(vp, nfhp->nfh_fh,
1149 nfhp->nfh_len, mode, 0, cred, p, &stateid, &lckp);
1150 if (error && vnode_vtype(vp) == VREG &&
1151 (mode == NFSV4OPEN_ACCESSWRITE ||
1152 nfstest_openallsetattr)) {
1154 * No Open stateid, so try and open the file
1157 if (mode == NFSV4OPEN_ACCESSWRITE)
1158 openerr = nfsrpc_open(vp, FWRITE, cred,
1161 openerr = nfsrpc_open(vp, FREAD, cred,
1164 (void) nfscl_getstateid(vp,
1165 nfhp->nfh_fh, nfhp->nfh_len,
1166 mode, 0, cred, p, &stateid, &lckp);
1170 error = nfsrpc_setattrrpc(vp, vap, &stateid, cred, p,
1171 rnap, attrflagp, stuff);
1173 error = nfsrpc_setaclrpc(vp, cred, p, aclp, &stateid,
1175 if (error == NFSERR_OPENMODE && mode == NFSV4OPEN_ACCESSREAD) {
1177 nmp->nm_state |= NFSSTA_OPENMODE;
1180 if (error == NFSERR_STALESTATEID)
1181 nfscl_initiate_recovery(nmp->nm_clp);
1183 nfscl_lockderef(lckp);
1185 (void) nfsrpc_close(vp, 0, p);
1186 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1187 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1188 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
1189 (void) nfs_catnap(PZERO, error, "nfs_setattr");
1190 } else if ((error == NFSERR_EXPIRED ||
1191 error == NFSERR_BADSTATEID) && clidrev != 0) {
1192 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1195 } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1196 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1197 error == NFSERR_BADSESSION ||
1198 (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
1199 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1200 expireret == 0 && clidrev != 0 && retrycnt < 4) ||
1201 (error == NFSERR_OPENMODE && mode == NFSV4OPEN_ACCESSREAD &&
1203 if (error && retrycnt >= 4)
1209 nfsrpc_setattrrpc(vnode_t vp, struct vattr *vap,
1210 nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p,
1211 struct nfsvattr *rnap, int *attrflagp, void *stuff)
1214 struct nfsrv_descript nfsd, *nd = &nfsd;
1216 nfsattrbit_t attrbits;
1219 NFSCL_REQSTART(nd, NFSPROC_SETATTR, vp);
1220 if (nd->nd_flag & ND_NFSV4)
1221 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
1222 vap->va_type = vnode_vtype(vp);
1223 nfscl_fillsattr(nd, vap, vp, NFSSATTR_FULL, 0);
1224 if (nd->nd_flag & ND_NFSV3) {
1225 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1227 } else if (nd->nd_flag & ND_NFSV4) {
1228 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1229 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1230 NFSGETATTR_ATTRBIT(&attrbits);
1231 (void) nfsrv_putattrbit(nd, &attrbits);
1233 error = nfscl_request(nd, vp, p, cred, stuff);
1236 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
1237 error = nfscl_wcc_data(nd, vp, rnap, attrflagp, NULL, stuff);
1238 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 && !error)
1239 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1240 if (!(nd->nd_flag & ND_NFSV3) && !nd->nd_repstat && !error)
1241 error = nfscl_postop_attr(nd, rnap, attrflagp, stuff);
1242 mbuf_freem(nd->nd_mrep);
1243 if (nd->nd_repstat && !error)
1244 error = nd->nd_repstat;
1252 nfsrpc_lookup(vnode_t dvp, char *name, int len, struct ucred *cred,
1253 NFSPROC_T *p, struct nfsvattr *dnap, struct nfsvattr *nap,
1254 struct nfsfh **nfhpp, int *attrflagp, int *dattrflagp, void *stuff)
1257 struct nfsrv_descript nfsd, *nd = &nfsd;
1258 struct nfsmount *nmp;
1261 nfsattrbit_t attrbits;
1262 int error = 0, lookupp = 0;
1266 if (vnode_vtype(dvp) != VDIR)
1268 nmp = VFSTONFS(vnode_mount(dvp));
1269 if (len > NFS_MAXNAMLEN)
1270 return (ENAMETOOLONG);
1271 if (NFSHASNFSV4(nmp) && len == 1 &&
1274 * Just return the current dir's fh.
1277 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) +
1278 np->n_fhp->nfh_len, M_NFSFH, M_WAITOK);
1279 nfhp->nfh_len = np->n_fhp->nfh_len;
1280 NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len);
1284 if (NFSHASNFSV4(nmp) && len == 2 &&
1285 name[0] == '.' && name[1] == '.') {
1287 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, dvp);
1289 NFSCL_REQSTART(nd, NFSPROC_LOOKUP, dvp);
1290 (void) nfsm_strtom(nd, name, len);
1292 if (nd->nd_flag & ND_NFSV4) {
1293 NFSGETATTR_ATTRBIT(&attrbits);
1294 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1295 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
1296 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1297 (void) nfsrv_putattrbit(nd, &attrbits);
1299 error = nfscl_request(nd, dvp, p, cred, stuff);
1302 if (nd->nd_repstat) {
1304 * When an NFSv4 Lookupp returns ENOENT, it means that
1305 * the lookup is at the root of an fs, so return this dir.
1307 if (nd->nd_repstat == NFSERR_NOENT && lookupp) {
1309 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) +
1310 np->n_fhp->nfh_len, M_NFSFH, M_WAITOK);
1311 nfhp->nfh_len = np->n_fhp->nfh_len;
1312 NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len);
1314 mbuf_freem(nd->nd_mrep);
1317 if (nd->nd_flag & ND_NFSV3)
1318 error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff);
1319 else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
1321 /* Load the directory attributes. */
1322 error = nfsm_loadattr(nd, dnap);
1328 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
1329 /* Load the directory attributes. */
1330 error = nfsm_loadattr(nd, dnap);
1334 /* Skip over the Lookup and GetFH operation status values. */
1335 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1337 error = nfsm_getfh(nd, nfhpp);
1341 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
1342 if ((nd->nd_flag & ND_NFSV3) && !error)
1343 error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff);
1345 mbuf_freem(nd->nd_mrep);
1346 if (!error && nd->nd_repstat)
1347 error = nd->nd_repstat;
1352 * Do a readlink rpc.
1355 nfsrpc_readlink(vnode_t vp, struct uio *uiop, struct ucred *cred,
1356 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
1359 struct nfsrv_descript nfsd, *nd = &nfsd;
1360 struct nfsnode *np = VTONFS(vp);
1361 nfsattrbit_t attrbits;
1362 int error, len, cangetattr = 1;
1365 NFSCL_REQSTART(nd, NFSPROC_READLINK, vp);
1366 if (nd->nd_flag & ND_NFSV4) {
1368 * And do a Getattr op.
1370 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1371 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1372 NFSGETATTR_ATTRBIT(&attrbits);
1373 (void) nfsrv_putattrbit(nd, &attrbits);
1375 error = nfscl_request(nd, vp, p, cred, stuff);
1378 if (nd->nd_flag & ND_NFSV3)
1379 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
1380 if (!nd->nd_repstat && !error) {
1381 NFSM_STRSIZ(len, NFS_MAXPATHLEN);
1383 * This seems weird to me, but must have been added to
1384 * FreeBSD for some reason. The only thing I can think of
1385 * is that there was/is some server that replies with
1386 * more link data than it should?
1388 if (len == NFS_MAXPATHLEN) {
1390 if (np->n_size > 0 && np->n_size < NFS_MAXPATHLEN) {
1396 error = nfsm_mbufuio(nd, uiop, len);
1397 if ((nd->nd_flag & ND_NFSV4) && !error && cangetattr)
1398 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
1400 if (nd->nd_repstat && !error)
1401 error = nd->nd_repstat;
1403 mbuf_freem(nd->nd_mrep);
1411 nfsrpc_read(vnode_t vp, struct uio *uiop, struct ucred *cred,
1412 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
1414 int error, expireret = 0, retrycnt;
1415 u_int32_t clidrev = 0;
1416 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1417 struct nfsnode *np = VTONFS(vp);
1418 struct ucred *newcred;
1419 struct nfsfh *nfhp = NULL;
1420 nfsv4stateid_t stateid;
1423 if (nmp->nm_clp != NULL)
1424 clidrev = nmp->nm_clp->nfsc_clientidrev;
1426 if (NFSHASNFSV4(nmp)) {
1428 newcred = NFSNEWCRED(cred);
1433 if (NFSHASNFSV4(nmp))
1434 (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
1435 NFSV4OPEN_ACCESSREAD, 0, newcred, p, &stateid,
1437 error = nfsrpc_readrpc(vp, uiop, newcred, &stateid, p, nap,
1439 if (error == NFSERR_OPENMODE) {
1441 nmp->nm_state |= NFSSTA_OPENMODE;
1444 if (error == NFSERR_STALESTATEID)
1445 nfscl_initiate_recovery(nmp->nm_clp);
1447 nfscl_lockderef(lckp);
1448 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1449 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1450 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
1451 (void) nfs_catnap(PZERO, error, "nfs_read");
1452 } else if ((error == NFSERR_EXPIRED ||
1453 error == NFSERR_BADSTATEID) && clidrev != 0) {
1454 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1457 } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1458 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1459 error == NFSERR_BADSESSION ||
1460 (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
1461 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1462 expireret == 0 && clidrev != 0 && retrycnt < 4) ||
1463 (error == NFSERR_OPENMODE && retrycnt < 4));
1464 if (error && retrycnt >= 4)
1466 if (NFSHASNFSV4(nmp))
1467 NFSFREECRED(newcred);
1472 * The actual read RPC.
1475 nfsrpc_readrpc(vnode_t vp, struct uio *uiop, struct ucred *cred,
1476 nfsv4stateid_t *stateidp, NFSPROC_T *p, struct nfsvattr *nap,
1477 int *attrflagp, void *stuff)
1480 int error = 0, len, retlen, tsiz, eof = 0;
1481 struct nfsrv_descript nfsd;
1482 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1483 struct nfsrv_descript *nd = &nfsd;
1488 tsiz = uio_uio_resid(uiop);
1489 tmp_off = uiop->uio_offset + tsiz;
1491 if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) {
1495 rsize = nmp->nm_rsize;
1500 len = (tsiz > rsize) ? rsize : tsiz;
1501 NFSCL_REQSTART(nd, NFSPROC_READ, vp);
1502 if (nd->nd_flag & ND_NFSV4)
1503 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
1504 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED * 3);
1505 if (nd->nd_flag & ND_NFSV2) {
1506 *tl++ = txdr_unsigned(uiop->uio_offset);
1507 *tl++ = txdr_unsigned(len);
1510 txdr_hyper(uiop->uio_offset, tl);
1511 *(tl + 2) = txdr_unsigned(len);
1514 * Since I can't do a Getattr for NFSv4 for Write, there
1515 * doesn't seem any point in doing one here, either.
1516 * (See the comment in nfsrpc_writerpc() for more info.)
1518 error = nfscl_request(nd, vp, p, cred, stuff);
1521 if (nd->nd_flag & ND_NFSV3) {
1522 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
1523 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
1524 error = nfsm_loadattr(nd, nap);
1528 if (nd->nd_repstat || error) {
1530 error = nd->nd_repstat;
1533 if (nd->nd_flag & ND_NFSV3) {
1534 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1535 eof = fxdr_unsigned(int, *(tl + 1));
1536 } else if (nd->nd_flag & ND_NFSV4) {
1537 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1538 eof = fxdr_unsigned(int, *tl);
1540 NFSM_STRSIZ(retlen, len);
1541 error = nfsm_mbufuio(nd, uiop, retlen);
1544 mbuf_freem(nd->nd_mrep);
1547 if (!(nd->nd_flag & ND_NFSV2)) {
1548 if (eof || retlen == 0)
1550 } else if (retlen < len)
1555 if (nd->nd_mrep != NULL)
1556 mbuf_freem(nd->nd_mrep);
1561 * nfs write operation
1562 * When called_from_strategy != 0, it should return EIO for an error that
1563 * indicates recovery is in progress, so that the buffer will be left
1564 * dirty and be written back to the server later. If it loops around,
1565 * the recovery thread could get stuck waiting for the buffer and recovery
1566 * will then deadlock.
1569 nfsrpc_write(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
1570 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
1571 void *stuff, int called_from_strategy)
1573 int error, expireret = 0, retrycnt, nostateid;
1574 u_int32_t clidrev = 0;
1575 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1576 struct nfsnode *np = VTONFS(vp);
1577 struct ucred *newcred;
1578 struct nfsfh *nfhp = NULL;
1579 nfsv4stateid_t stateid;
1583 if (nmp->nm_clp != NULL)
1584 clidrev = nmp->nm_clp->nfsc_clientidrev;
1586 if (NFSHASNFSV4(nmp)) {
1587 newcred = NFSNEWCRED(cred);
1594 if (NFSHASNFSV4(nmp)) {
1595 (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
1596 NFSV4OPEN_ACCESSWRITE, 0, newcred, p, &stateid,
1598 if (stateid.other[0] == 0 && stateid.other[1] == 0 &&
1599 stateid.other[2] == 0) {
1601 NFSCL_DEBUG(1, "stateid0 in write\n");
1606 * If there is no stateid for NFSv4, it means this is an
1607 * extraneous write after close. Basically a poorly
1608 * implemented buffer cache. Just don't do the write.
1613 error = nfsrpc_writerpc(vp, uiop, iomode, must_commit,
1614 newcred, &stateid, p, nap, attrflagp, stuff);
1615 if (error == NFSERR_STALESTATEID)
1616 nfscl_initiate_recovery(nmp->nm_clp);
1618 nfscl_lockderef(lckp);
1619 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1620 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1621 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
1622 (void) nfs_catnap(PZERO, error, "nfs_write");
1623 } else if ((error == NFSERR_EXPIRED ||
1624 error == NFSERR_BADSTATEID) && clidrev != 0) {
1625 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1628 } while (error == NFSERR_GRACE || error == NFSERR_DELAY ||
1629 ((error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION ||
1630 error == NFSERR_STALEDONTRECOVER) && called_from_strategy == 0) ||
1631 (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
1632 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1633 expireret == 0 && clidrev != 0 && retrycnt < 4));
1634 if (error != 0 && (retrycnt >= 4 ||
1635 ((error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION ||
1636 error == NFSERR_STALEDONTRECOVER) && called_from_strategy != 0)))
1638 if (NFSHASNFSV4(nmp))
1639 NFSFREECRED(newcred);
1644 * The actual write RPC.
1647 nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode,
1648 int *must_commit, struct ucred *cred, nfsv4stateid_t *stateidp,
1649 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
1652 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1653 struct nfsnode *np = VTONFS(vp);
1654 int error = 0, len, tsiz, rlen, commit, committed = NFSWRITE_FILESYNC;
1655 int wccflag = 0, wsize;
1657 struct nfsrv_descript nfsd;
1658 struct nfsrv_descript *nd = &nfsd;
1659 nfsattrbit_t attrbits;
1662 KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1"));
1664 tsiz = uio_uio_resid(uiop);
1665 tmp_off = uiop->uio_offset + tsiz;
1667 if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) {
1671 wsize = nmp->nm_wsize;
1673 nd->nd_mrep = NULL; /* NFSv2 sometimes does a write with */
1674 nd->nd_repstat = 0; /* uio_resid == 0, so the while is not done */
1677 len = (tsiz > wsize) ? wsize : tsiz;
1678 NFSCL_REQSTART(nd, NFSPROC_WRITE, vp);
1679 if (nd->nd_flag & ND_NFSV4) {
1680 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
1681 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+2*NFSX_UNSIGNED);
1682 txdr_hyper(uiop->uio_offset, tl);
1684 *tl++ = txdr_unsigned(*iomode);
1685 *tl = txdr_unsigned(len);
1686 } else if (nd->nd_flag & ND_NFSV3) {
1687 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+3*NFSX_UNSIGNED);
1688 txdr_hyper(uiop->uio_offset, tl);
1690 *tl++ = txdr_unsigned(len);
1691 *tl++ = txdr_unsigned(*iomode);
1692 *tl = txdr_unsigned(len);
1696 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1698 * Not sure why someone changed this, since the
1699 * RFC clearly states that "beginoffset" and
1700 * "totalcount" are ignored, but it wouldn't
1701 * surprise me if there's a busted server out there.
1703 /* Set both "begin" and "current" to non-garbage. */
1704 x = txdr_unsigned((u_int32_t)uiop->uio_offset);
1705 *tl++ = x; /* "begin offset" */
1706 *tl++ = x; /* "current offset" */
1707 x = txdr_unsigned(len);
1708 *tl++ = x; /* total to this offset */
1709 *tl = x; /* size of this write */
1712 nfsm_uiombuf(nd, uiop, len);
1714 * Although it is tempting to do a normal Getattr Op in the
1715 * NFSv4 compound, the result can be a nearly hung client
1716 * system if the Getattr asks for Owner and/or OwnerGroup.
1717 * It occurs when the client can't map either the Owner or
1718 * Owner_group name in the Getattr reply to a uid/gid. When
1719 * there is a cache miss, the kernel does an upcall to the
1720 * nfsuserd. Then, it can try and read the local /etc/passwd
1721 * or /etc/group file. It can then block in getnewbuf(),
1722 * waiting for dirty writes to be pushed to the NFS server.
1723 * The only reason this doesn't result in a complete
1724 * deadlock, is that the upcall times out and allows
1725 * the write to complete. However, progress is so slow
1726 * that it might just as well be deadlocked.
1727 * As such, we get the rest of the attributes, but not
1728 * Owner or Owner_group.
1729 * nb: nfscl_loadattrcache() needs to be told that these
1730 * partial attributes from a write rpc are being
1731 * passed in, via a argument flag.
1733 if (nd->nd_flag & ND_NFSV4) {
1734 NFSWRITEGETATTR_ATTRBIT(&attrbits);
1735 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1736 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1737 (void) nfsrv_putattrbit(nd, &attrbits);
1739 error = nfscl_request(nd, vp, p, cred, stuff);
1742 if (nd->nd_repstat) {
1744 * In case the rpc gets retried, roll
1745 * the uio fileds changed by nfsm_uiombuf()
1748 uiop->uio_offset -= len;
1749 uio_uio_resid_add(uiop, len);
1750 uio_iov_base_add(uiop, -len);
1751 uio_iov_len_add(uiop, len);
1753 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1754 error = nfscl_wcc_data(nd, vp, nap, attrflagp,
1759 if (!nd->nd_repstat) {
1760 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1761 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED
1763 rlen = fxdr_unsigned(int, *tl++);
1767 } else if (rlen < len) {
1768 backup = len - rlen;
1769 uio_iov_base_add(uiop, -(backup));
1770 uio_iov_len_add(uiop, backup);
1771 uiop->uio_offset -= backup;
1772 uio_uio_resid_add(uiop, backup);
1775 commit = fxdr_unsigned(int, *tl++);
1778 * Return the lowest commitment level
1779 * obtained by any of the RPCs.
1781 if (committed == NFSWRITE_FILESYNC)
1783 else if (committed == NFSWRITE_DATASYNC &&
1784 commit == NFSWRITE_UNSTABLE)
1787 if (!NFSHASWRITEVERF(nmp)) {
1788 NFSBCOPY((caddr_t)tl,
1789 (caddr_t)&nmp->nm_verf[0],
1791 NFSSETWRITEVERF(nmp);
1792 } else if (NFSBCMP(tl, nmp->nm_verf,
1795 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
1799 if (nd->nd_flag & ND_NFSV4)
1800 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1801 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV4)) {
1802 error = nfsm_loadattr(nd, nap);
1804 *attrflagp = NFS_LATTR_NOSHRINK;
1807 error = nd->nd_repstat;
1811 NFSWRITERPC_SETTIME(wccflag, np, nap, (nd->nd_flag & ND_NFSV4));
1812 mbuf_freem(nd->nd_mrep);
1817 if (nd->nd_mrep != NULL)
1818 mbuf_freem(nd->nd_mrep);
1819 *iomode = committed;
1820 if (nd->nd_repstat && !error)
1821 error = nd->nd_repstat;
1827 * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the
1828 * mode set to specify the file type and the size field for rdev.
1831 nfsrpc_mknod(vnode_t dvp, char *name, int namelen, struct vattr *vap,
1832 u_int32_t rdev, enum vtype vtyp, struct ucred *cred, NFSPROC_T *p,
1833 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
1834 int *attrflagp, int *dattrflagp, void *dstuff)
1838 struct nfsrv_descript nfsd, *nd = &nfsd;
1839 nfsattrbit_t attrbits;
1844 if (namelen > NFS_MAXNAMLEN)
1845 return (ENAMETOOLONG);
1846 NFSCL_REQSTART(nd, NFSPROC_MKNOD, dvp);
1847 if (nd->nd_flag & ND_NFSV4) {
1848 if (vtyp == VBLK || vtyp == VCHR) {
1849 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1850 *tl++ = vtonfsv34_type(vtyp);
1851 *tl++ = txdr_unsigned(NFSMAJOR(rdev));
1852 *tl = txdr_unsigned(NFSMINOR(rdev));
1854 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1855 *tl = vtonfsv34_type(vtyp);
1858 (void) nfsm_strtom(nd, name, namelen);
1859 if (nd->nd_flag & ND_NFSV3) {
1860 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1861 *tl = vtonfsv34_type(vtyp);
1863 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
1864 nfscl_fillsattr(nd, vap, dvp, 0, 0);
1865 if ((nd->nd_flag & ND_NFSV3) &&
1866 (vtyp == VCHR || vtyp == VBLK)) {
1867 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1868 *tl++ = txdr_unsigned(NFSMAJOR(rdev));
1869 *tl = txdr_unsigned(NFSMINOR(rdev));
1871 if (nd->nd_flag & ND_NFSV4) {
1872 NFSGETATTR_ATTRBIT(&attrbits);
1873 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1874 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
1875 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1876 (void) nfsrv_putattrbit(nd, &attrbits);
1878 if (nd->nd_flag & ND_NFSV2)
1879 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZERDEV, rdev);
1880 error = nfscl_request(nd, dvp, p, cred, dstuff);
1883 if (nd->nd_flag & ND_NFSV4)
1884 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
1885 if (!nd->nd_repstat) {
1886 if (nd->nd_flag & ND_NFSV4) {
1887 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1888 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1892 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
1896 if (nd->nd_flag & ND_NFSV3)
1897 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
1898 if (!error && nd->nd_repstat)
1899 error = nd->nd_repstat;
1901 mbuf_freem(nd->nd_mrep);
1906 * nfs file create call
1907 * Mostly just call the approriate routine. (I separated out v4, so that
1908 * error recovery wouldn't be as difficult.)
1911 nfsrpc_create(vnode_t dvp, char *name, int namelen, struct vattr *vap,
1912 nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p,
1913 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
1914 int *attrflagp, int *dattrflagp, void *dstuff)
1916 int error = 0, newone, expireret = 0, retrycnt, unlocked;
1917 struct nfsclowner *owp;
1918 struct nfscldeleg *dp;
1919 struct nfsmount *nmp = VFSTONFS(vnode_mount(dvp));
1922 if (NFSHASNFSV4(nmp)) {
1926 error = nfscl_open(dvp, NULL, 0, (NFSV4OPEN_ACCESSWRITE |
1927 NFSV4OPEN_ACCESSREAD), 0, cred, p, &owp, NULL, &newone,
1931 if (nmp->nm_clp != NULL)
1932 clidrev = nmp->nm_clp->nfsc_clientidrev;
1935 if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 ||
1936 nfs_numnfscbd == 0 || retrycnt > 0)
1937 error = nfsrpc_createv4(dvp, name, namelen, vap, cverf,
1938 fmode, owp, &dp, cred, p, dnap, nnap, nfhpp,
1939 attrflagp, dattrflagp, dstuff, &unlocked);
1941 error = nfsrpc_getcreatelayout(dvp, name, namelen, vap,
1942 cverf, fmode, owp, &dp, cred, p, dnap, nnap, nfhpp,
1943 attrflagp, dattrflagp, dstuff, &unlocked);
1945 * There is no need to invalidate cached attributes here,
1946 * since new post-delegation issue attributes are always
1947 * returned by nfsrpc_createv4() and these will update the
1951 (void) nfscl_deleg(nmp->nm_mountp, owp->nfsow_clp,
1952 (*nfhpp)->nfh_fh, (*nfhpp)->nfh_len, cred, p, &dp);
1953 nfscl_ownerrelease(nmp, owp, error, newone, unlocked);
1954 if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
1955 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1956 error == NFSERR_BADSESSION) {
1957 (void) nfs_catnap(PZERO, error, "nfs_open");
1958 } else if ((error == NFSERR_EXPIRED ||
1959 error == NFSERR_BADSTATEID) && clidrev != 0) {
1960 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1963 } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
1964 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1965 error == NFSERR_BADSESSION ||
1966 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1967 expireret == 0 && clidrev != 0 && retrycnt < 4));
1968 if (error && retrycnt >= 4)
1971 error = nfsrpc_createv23(dvp, name, namelen, vap, cverf,
1972 fmode, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp,
1979 * The create rpc for v2 and 3.
1982 nfsrpc_createv23(vnode_t dvp, char *name, int namelen, struct vattr *vap,
1983 nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p,
1984 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
1985 int *attrflagp, int *dattrflagp, void *dstuff)
1989 struct nfsrv_descript nfsd, *nd = &nfsd;
1994 if (namelen > NFS_MAXNAMLEN)
1995 return (ENAMETOOLONG);
1996 NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp);
1997 (void) nfsm_strtom(nd, name, namelen);
1998 if (nd->nd_flag & ND_NFSV3) {
1999 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2000 if (fmode & O_EXCL) {
2001 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE);
2002 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2003 *tl++ = cverf.lval[0];
2004 *tl = cverf.lval[1];
2006 *tl = txdr_unsigned(NFSCREATE_UNCHECKED);
2007 nfscl_fillsattr(nd, vap, dvp, 0, 0);
2010 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZE0, 0);
2012 error = nfscl_request(nd, dvp, p, cred, dstuff);
2015 if (nd->nd_repstat == 0) {
2016 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
2020 if (nd->nd_flag & ND_NFSV3)
2021 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2022 if (nd->nd_repstat != 0 && error == 0)
2023 error = nd->nd_repstat;
2025 mbuf_freem(nd->nd_mrep);
2030 nfsrpc_createv4(vnode_t dvp, char *name, int namelen, struct vattr *vap,
2031 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp,
2032 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
2033 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
2034 int *dattrflagp, void *dstuff, int *unlockedp)
2037 int error = 0, deleg, newone, ret, acesize, limitby;
2038 struct nfsrv_descript nfsd, *nd = &nfsd;
2039 struct nfsclopen *op;
2040 struct nfscldeleg *dp = NULL;
2043 nfsattrbit_t attrbits;
2044 nfsv4stateid_t stateid;
2046 struct nfsmount *nmp;
2047 struct nfsclsession *tsep;
2049 nmp = VFSTONFS(dvp->v_mount);
2056 if (namelen > NFS_MAXNAMLEN)
2057 return (ENAMETOOLONG);
2058 NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp);
2060 * For V4, this is actually an Open op.
2062 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2063 *tl++ = txdr_unsigned(owp->nfsow_seqid);
2064 *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
2065 NFSV4OPEN_ACCESSREAD);
2066 *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE);
2067 tsep = nfsmnt_mdssession(nmp);
2068 *tl++ = tsep->nfsess_clientid.lval[0];
2069 *tl = tsep->nfsess_clientid.lval[1];
2070 (void) nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN);
2071 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2072 *tl++ = txdr_unsigned(NFSV4OPEN_CREATE);
2073 if (fmode & O_EXCL) {
2074 if (NFSHASNFSV4N(nmp)) {
2075 if (NFSHASSESSPERSIST(nmp)) {
2076 /* Use GUARDED for persistent sessions. */
2077 *tl = txdr_unsigned(NFSCREATE_GUARDED);
2078 nfscl_fillsattr(nd, vap, dvp, 0, 0);
2080 /* Otherwise, use EXCLUSIVE4_1. */
2081 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41);
2082 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2083 *tl++ = cverf.lval[0];
2084 *tl = cverf.lval[1];
2085 nfscl_fillsattr(nd, vap, dvp, 0, 0);
2089 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE);
2090 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2091 *tl++ = cverf.lval[0];
2092 *tl = cverf.lval[1];
2095 *tl = txdr_unsigned(NFSCREATE_UNCHECKED);
2096 nfscl_fillsattr(nd, vap, dvp, 0, 0);
2098 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2099 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
2100 (void) nfsm_strtom(nd, name, namelen);
2101 /* Get the new file's handle and attributes. */
2102 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2103 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
2104 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2105 NFSGETATTR_ATTRBIT(&attrbits);
2106 (void) nfsrv_putattrbit(nd, &attrbits);
2107 /* Get the directory's post-op attributes. */
2108 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2109 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2110 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0);
2111 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2112 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2113 (void) nfsrv_putattrbit(nd, &attrbits);
2114 error = nfscl_request(nd, dvp, p, cred, dstuff);
2117 NFSCL_INCRSEQID(owp->nfsow_seqid, nd);
2118 if (nd->nd_repstat == 0) {
2119 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
2121 stateid.seqid = *tl++;
2122 stateid.other[0] = *tl++;
2123 stateid.other[1] = *tl++;
2124 stateid.other[2] = *tl;
2125 rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
2126 (void) nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
2127 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2128 deleg = fxdr_unsigned(int, *tl);
2129 if (deleg == NFSV4OPEN_DELEGATEREAD ||
2130 deleg == NFSV4OPEN_DELEGATEWRITE) {
2131 if (!(owp->nfsow_clp->nfsc_flags &
2132 NFSCLFLAGS_FIRSTDELEG))
2133 owp->nfsow_clp->nfsc_flags |=
2134 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
2135 MALLOC(dp, struct nfscldeleg *,
2136 sizeof (struct nfscldeleg) + NFSX_V4FHMAX,
2137 M_NFSCLDELEG, M_WAITOK);
2138 LIST_INIT(&dp->nfsdl_owner);
2139 LIST_INIT(&dp->nfsdl_lock);
2140 dp->nfsdl_clp = owp->nfsow_clp;
2141 newnfs_copyincred(cred, &dp->nfsdl_cred);
2142 nfscl_lockinit(&dp->nfsdl_rwlock);
2143 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
2145 dp->nfsdl_stateid.seqid = *tl++;
2146 dp->nfsdl_stateid.other[0] = *tl++;
2147 dp->nfsdl_stateid.other[1] = *tl++;
2148 dp->nfsdl_stateid.other[2] = *tl++;
2149 ret = fxdr_unsigned(int, *tl);
2150 if (deleg == NFSV4OPEN_DELEGATEWRITE) {
2151 dp->nfsdl_flags = NFSCLDL_WRITE;
2153 * Indicates how much the file can grow.
2155 NFSM_DISSECT(tl, u_int32_t *,
2157 limitby = fxdr_unsigned(int, *tl++);
2159 case NFSV4OPEN_LIMITSIZE:
2160 dp->nfsdl_sizelimit = fxdr_hyper(tl);
2162 case NFSV4OPEN_LIMITBLOCKS:
2163 dp->nfsdl_sizelimit =
2164 fxdr_unsigned(u_int64_t, *tl++);
2165 dp->nfsdl_sizelimit *=
2166 fxdr_unsigned(u_int64_t, *tl);
2169 error = NFSERR_BADXDR;
2173 dp->nfsdl_flags = NFSCLDL_READ;
2176 dp->nfsdl_flags |= NFSCLDL_RECALL;
2177 error = nfsrv_dissectace(nd, &dp->nfsdl_ace, &ret,
2181 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
2182 error = NFSERR_BADXDR;
2185 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
2188 /* Get rid of the PutFH and Getattr status values. */
2189 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
2190 /* Load the directory attributes. */
2191 error = nfsm_loadattr(nd, dnap);
2195 if (dp != NULL && *attrflagp) {
2196 dp->nfsdl_change = nnap->na_filerev;
2197 dp->nfsdl_modtime = nnap->na_mtime;
2198 dp->nfsdl_flags |= NFSCLDL_MODTIMESET;
2201 * We can now complete the Open state.
2205 dp->nfsdl_fhlen = nfhp->nfh_len;
2206 NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, nfhp->nfh_len);
2209 * Get an Open structure that will be
2210 * attached to the OpenOwner, acquired already.
2212 error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len,
2213 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0,
2214 cred, p, NULL, &op, &newone, NULL, 0);
2217 op->nfso_stateid = stateid;
2218 newnfs_copyincred(cred, &op->nfso_cred);
2219 if ((rflags & NFSV4OPEN_RESULTCONFIRM)) {
2221 ret = nfsrpc_openconfirm(dvp, nfhp->nfh_fh,
2222 nfhp->nfh_len, op, cred, p);
2223 if (ret == NFSERR_DELAY)
2224 (void) nfs_catnap(PZERO, ret, "nfs_create");
2225 } while (ret == NFSERR_DELAY);
2230 * If the server is handing out delegations, but we didn't
2231 * get one because an OpenConfirm was required, try the
2232 * Open again, to get a delegation. This is a harmless no-op,
2233 * from a server's point of view.
2235 if ((rflags & NFSV4OPEN_RESULTCONFIRM) &&
2236 (owp->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) &&
2237 !error && dp == NULL) {
2239 ret = nfsrpc_openrpc(VFSTONFS(vnode_mount(dvp)), dvp,
2240 np->n_fhp->nfh_fh, np->n_fhp->nfh_len,
2241 nfhp->nfh_fh, nfhp->nfh_len,
2242 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), op,
2243 name, namelen, &dp, 0, 0x0, cred, p, 0, 1);
2244 if (ret == NFSERR_DELAY)
2245 (void) nfs_catnap(PZERO, ret, "nfs_crt2");
2246 } while (ret == NFSERR_DELAY);
2249 FREE((caddr_t)dp, M_NFSCLDELEG);
2252 if (ret == NFSERR_STALECLIENTID ||
2253 ret == NFSERR_STALEDONTRECOVER ||
2254 ret == NFSERR_BADSESSION)
2258 nfscl_openrelease(nmp, op, error, newone);
2261 if (nd->nd_repstat != 0 && error == 0)
2262 error = nd->nd_repstat;
2263 if (error == NFSERR_STALECLIENTID)
2264 nfscl_initiate_recovery(owp->nfsow_clp);
2268 else if (dp != NULL)
2269 FREE((caddr_t)dp, M_NFSCLDELEG);
2270 mbuf_freem(nd->nd_mrep);
2278 nfsrpc_remove(vnode_t dvp, char *name, int namelen, vnode_t vp,
2279 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp,
2283 struct nfsrv_descript nfsd, *nd = &nfsd;
2285 struct nfsmount *nmp;
2286 nfsv4stateid_t dstateid;
2287 int error, ret = 0, i;
2290 if (namelen > NFS_MAXNAMLEN)
2291 return (ENAMETOOLONG);
2292 nmp = VFSTONFS(vnode_mount(dvp));
2294 if (NFSHASNFSV4(nmp) && ret == 0) {
2295 ret = nfscl_removedeleg(vp, p, &dstateid);
2297 NFSCL_REQSTART(nd, NFSPROC_RETDELEGREMOVE, vp);
2298 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID +
2300 if (NFSHASNFSV4N(nmp))
2303 *tl++ = dstateid.seqid;
2304 *tl++ = dstateid.other[0];
2305 *tl++ = dstateid.other[1];
2306 *tl++ = dstateid.other[2];
2307 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2309 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
2310 np->n_fhp->nfh_len, 0);
2311 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2312 *tl = txdr_unsigned(NFSV4OP_REMOVE);
2318 NFSCL_REQSTART(nd, NFSPROC_REMOVE, dvp);
2319 (void) nfsm_strtom(nd, name, namelen);
2320 error = nfscl_request(nd, dvp, p, cred, dstuff);
2323 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
2324 /* For NFSv4, parse out any Delereturn replies. */
2325 if (ret > 0 && nd->nd_repstat != 0 &&
2326 (nd->nd_flag & ND_NOMOREDATA)) {
2328 * If the Delegreturn failed, try again without
2329 * it. The server will Recall, as required.
2331 mbuf_freem(nd->nd_mrep);
2334 for (i = 0; i < (ret * 2); i++) {
2335 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
2337 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2339 nd->nd_flag |= ND_NOMOREDATA;
2342 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2344 if (nd->nd_repstat && !error)
2345 error = nd->nd_repstat;
2347 mbuf_freem(nd->nd_mrep);
2352 * Do an nfs rename rpc.
2355 nfsrpc_rename(vnode_t fdvp, vnode_t fvp, char *fnameptr, int fnamelen,
2356 vnode_t tdvp, vnode_t tvp, char *tnameptr, int tnamelen, struct ucred *cred,
2357 NFSPROC_T *p, struct nfsvattr *fnap, struct nfsvattr *tnap,
2358 int *fattrflagp, int *tattrflagp, void *fstuff, void *tstuff)
2361 struct nfsrv_descript nfsd, *nd = &nfsd;
2362 struct nfsmount *nmp;
2364 nfsattrbit_t attrbits;
2365 nfsv4stateid_t fdstateid, tdstateid;
2366 int error = 0, ret = 0, gottd = 0, gotfd = 0, i;
2370 nmp = VFSTONFS(vnode_mount(fdvp));
2371 if (fnamelen > NFS_MAXNAMLEN || tnamelen > NFS_MAXNAMLEN)
2372 return (ENAMETOOLONG);
2374 if (NFSHASNFSV4(nmp) && ret == 0) {
2375 ret = nfscl_renamedeleg(fvp, &fdstateid, &gotfd, tvp,
2376 &tdstateid, &gottd, p);
2377 if (gotfd && gottd) {
2378 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME2, fvp);
2380 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, fvp);
2382 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, tvp);
2385 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2386 if (NFSHASNFSV4N(nmp))
2389 *tl++ = fdstateid.seqid;
2390 *tl++ = fdstateid.other[0];
2391 *tl++ = fdstateid.other[1];
2392 *tl = fdstateid.other[2];
2394 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2395 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2397 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
2398 np->n_fhp->nfh_len, 0);
2399 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2400 *tl = txdr_unsigned(NFSV4OP_DELEGRETURN);
2404 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2405 if (NFSHASNFSV4N(nmp))
2408 *tl++ = tdstateid.seqid;
2409 *tl++ = tdstateid.other[0];
2410 *tl++ = tdstateid.other[1];
2411 *tl = tdstateid.other[2];
2414 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2415 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2417 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
2418 np->n_fhp->nfh_len, 0);
2419 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2420 *tl = txdr_unsigned(NFSV4OP_SAVEFH);
2426 NFSCL_REQSTART(nd, NFSPROC_RENAME, fdvp);
2427 if (nd->nd_flag & ND_NFSV4) {
2428 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2429 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2430 NFSWCCATTR_ATTRBIT(&attrbits);
2431 (void) nfsrv_putattrbit(nd, &attrbits);
2432 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2433 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2434 (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh,
2435 VTONFS(tdvp)->n_fhp->nfh_len, 0);
2436 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2437 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2438 (void) nfsrv_putattrbit(nd, &attrbits);
2439 nd->nd_flag |= ND_V4WCCATTR;
2440 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2441 *tl = txdr_unsigned(NFSV4OP_RENAME);
2443 (void) nfsm_strtom(nd, fnameptr, fnamelen);
2444 if (!(nd->nd_flag & ND_NFSV4))
2445 (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh,
2446 VTONFS(tdvp)->n_fhp->nfh_len, 0);
2447 (void) nfsm_strtom(nd, tnameptr, tnamelen);
2448 error = nfscl_request(nd, fdvp, p, cred, fstuff);
2451 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
2452 /* For NFSv4, parse out any Delereturn replies. */
2453 if (ret > 0 && nd->nd_repstat != 0 &&
2454 (nd->nd_flag & ND_NOMOREDATA)) {
2456 * If the Delegreturn failed, try again without
2457 * it. The server will Recall, as required.
2459 mbuf_freem(nd->nd_mrep);
2462 for (i = 0; i < (ret * 2); i++) {
2463 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
2465 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2467 if (i == 0 && ret > 1) {
2469 * If the Delegreturn failed, try again
2470 * without it. The server will Recall, as
2472 * If ret > 1, the first iteration of this
2473 * loop is the second DelegReturn result.
2475 mbuf_freem(nd->nd_mrep);
2478 nd->nd_flag |= ND_NOMOREDATA;
2483 /* Now, the first wcc attribute reply. */
2484 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
2485 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2487 nd->nd_flag |= ND_NOMOREDATA;
2489 error = nfscl_wcc_data(nd, fdvp, fnap, fattrflagp, NULL,
2491 /* and the second wcc attribute reply. */
2492 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 &&
2494 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2496 nd->nd_flag |= ND_NOMOREDATA;
2499 error = nfscl_wcc_data(nd, tdvp, tnap, tattrflagp,
2502 if (nd->nd_repstat && !error)
2503 error = nd->nd_repstat;
2505 mbuf_freem(nd->nd_mrep);
2510 * nfs hard link create rpc
2513 nfsrpc_link(vnode_t dvp, vnode_t vp, char *name, int namelen,
2514 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
2515 struct nfsvattr *nap, int *attrflagp, int *dattrflagp, void *dstuff)
2518 struct nfsrv_descript nfsd, *nd = &nfsd;
2519 nfsattrbit_t attrbits;
2524 if (namelen > NFS_MAXNAMLEN)
2525 return (ENAMETOOLONG);
2526 NFSCL_REQSTART(nd, NFSPROC_LINK, vp);
2527 if (nd->nd_flag & ND_NFSV4) {
2528 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2529 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2531 (void) nfsm_fhtom(nd, VTONFS(dvp)->n_fhp->nfh_fh,
2532 VTONFS(dvp)->n_fhp->nfh_len, 0);
2533 if (nd->nd_flag & ND_NFSV4) {
2534 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2535 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2536 NFSWCCATTR_ATTRBIT(&attrbits);
2537 (void) nfsrv_putattrbit(nd, &attrbits);
2538 nd->nd_flag |= ND_V4WCCATTR;
2539 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2540 *tl = txdr_unsigned(NFSV4OP_LINK);
2542 (void) nfsm_strtom(nd, name, namelen);
2543 error = nfscl_request(nd, vp, p, cred, dstuff);
2546 if (nd->nd_flag & ND_NFSV3) {
2547 error = nfscl_postop_attr(nd, nap, attrflagp, dstuff);
2549 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp,
2551 } else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
2553 * First, parse out the PutFH and Getattr result.
2555 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2557 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2559 nd->nd_flag |= ND_NOMOREDATA;
2561 * Get the pre-op attributes.
2563 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2565 if (nd->nd_repstat && !error)
2566 error = nd->nd_repstat;
2568 mbuf_freem(nd->nd_mrep);
2573 * nfs symbolic link create rpc
2576 nfsrpc_symlink(vnode_t dvp, char *name, int namelen, char *target,
2577 struct vattr *vap, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
2578 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
2579 int *dattrflagp, void *dstuff)
2582 struct nfsrv_descript nfsd, *nd = &nfsd;
2583 struct nfsmount *nmp;
2584 int slen, error = 0;
2589 nmp = VFSTONFS(vnode_mount(dvp));
2590 slen = strlen(target);
2591 if (slen > NFS_MAXPATHLEN || namelen > NFS_MAXNAMLEN)
2592 return (ENAMETOOLONG);
2593 NFSCL_REQSTART(nd, NFSPROC_SYMLINK, dvp);
2594 if (nd->nd_flag & ND_NFSV4) {
2595 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2596 *tl = txdr_unsigned(NFLNK);
2597 (void) nfsm_strtom(nd, target, slen);
2599 (void) nfsm_strtom(nd, name, namelen);
2600 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
2601 nfscl_fillsattr(nd, vap, dvp, 0, 0);
2602 if (!(nd->nd_flag & ND_NFSV4))
2603 (void) nfsm_strtom(nd, target, slen);
2604 if (nd->nd_flag & ND_NFSV2)
2605 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0);
2606 error = nfscl_request(nd, dvp, p, cred, dstuff);
2609 if (nd->nd_flag & ND_NFSV4)
2610 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2611 if ((nd->nd_flag & ND_NFSV3) && !error) {
2612 if (!nd->nd_repstat)
2613 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
2615 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp,
2618 if (nd->nd_repstat && !error)
2619 error = nd->nd_repstat;
2620 mbuf_freem(nd->nd_mrep);
2622 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
2623 * Only do this if vfs.nfs.ignore_eexist is set.
2624 * Never do this for NFSv4.1 or later minor versions, since sessions
2625 * should guarantee "exactly once" RPC semantics.
2627 if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) ||
2628 nmp->nm_minorvers == 0))
2637 nfsrpc_mkdir(vnode_t dvp, char *name, int namelen, struct vattr *vap,
2638 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
2639 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
2640 int *dattrflagp, void *dstuff)
2643 struct nfsrv_descript nfsd, *nd = &nfsd;
2644 nfsattrbit_t attrbits;
2647 struct nfsmount *nmp;
2652 nmp = VFSTONFS(vnode_mount(dvp));
2653 fhp = VTONFS(dvp)->n_fhp;
2654 if (namelen > NFS_MAXNAMLEN)
2655 return (ENAMETOOLONG);
2656 NFSCL_REQSTART(nd, NFSPROC_MKDIR, dvp);
2657 if (nd->nd_flag & ND_NFSV4) {
2658 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2659 *tl = txdr_unsigned(NFDIR);
2661 (void) nfsm_strtom(nd, name, namelen);
2662 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0);
2663 if (nd->nd_flag & ND_NFSV4) {
2664 NFSGETATTR_ATTRBIT(&attrbits);
2665 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2666 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
2667 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2668 (void) nfsrv_putattrbit(nd, &attrbits);
2669 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2670 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2671 (void) nfsm_fhtom(nd, fhp->nfh_fh, fhp->nfh_len, 0);
2672 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2673 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2674 (void) nfsrv_putattrbit(nd, &attrbits);
2676 error = nfscl_request(nd, dvp, p, cred, dstuff);
2679 if (nd->nd_flag & ND_NFSV4)
2680 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2681 if (!nd->nd_repstat && !error) {
2682 if (nd->nd_flag & ND_NFSV4) {
2683 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2684 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
2687 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
2688 if (error == 0 && (nd->nd_flag & ND_NFSV4) != 0) {
2689 /* Get rid of the PutFH and Getattr status values. */
2690 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
2691 /* Load the directory attributes. */
2692 error = nfsm_loadattr(nd, dnap);
2697 if ((nd->nd_flag & ND_NFSV3) && !error)
2698 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2699 if (nd->nd_repstat && !error)
2700 error = nd->nd_repstat;
2702 mbuf_freem(nd->nd_mrep);
2704 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
2705 * Only do this if vfs.nfs.ignore_eexist is set.
2706 * Never do this for NFSv4.1 or later minor versions, since sessions
2707 * should guarantee "exactly once" RPC semantics.
2709 if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) ||
2710 nmp->nm_minorvers == 0))
2716 * nfs remove directory call
2719 nfsrpc_rmdir(vnode_t dvp, char *name, int namelen, struct ucred *cred,
2720 NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp, void *dstuff)
2722 struct nfsrv_descript nfsd, *nd = &nfsd;
2726 if (namelen > NFS_MAXNAMLEN)
2727 return (ENAMETOOLONG);
2728 NFSCL_REQSTART(nd, NFSPROC_RMDIR, dvp);
2729 (void) nfsm_strtom(nd, name, namelen);
2730 error = nfscl_request(nd, dvp, p, cred, dstuff);
2733 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
2734 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2735 if (nd->nd_repstat && !error)
2736 error = nd->nd_repstat;
2737 mbuf_freem(nd->nd_mrep);
2739 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
2741 if (error == ENOENT)
2748 * Always returns with either uio_resid unchanged, if you are at the
2749 * end of the directory, or uio_resid == 0, with all DIRBLKSIZ chunks
2751 * I felt this would allow caching of directory blocks more easily
2752 * than returning a pertially filled block.
2753 * Directory offset cookies:
2754 * Oh my, what to do with them...
2755 * I can think of three ways to deal with them:
2756 * 1 - have the layer above these RPCs maintain a map between logical
2757 * directory byte offsets and the NFS directory offset cookies
2758 * 2 - pass the opaque directory offset cookies up into userland
2759 * and let the libc functions deal with them, via the system call
2760 * 3 - return them to userland in the "struct dirent", so future versions
2761 * of libc can use them and do whatever is necessary to make things work
2762 * above these rpc calls, in the meantime
2763 * For now, I do #3 by "hiding" the directory offset cookies after the
2764 * d_name field in struct dirent. This is space inside d_reclen that
2765 * will be ignored by anything that doesn't know about them.
2766 * The directory offset cookies are filled in as the last 8 bytes of
2767 * each directory entry, after d_name. Someday, the userland libc
2768 * functions may be able to use these. In the meantime, it satisfies
2769 * OpenBSD's requirements for cookies being returned.
2770 * If expects the directory offset cookie for the read to be in uio_offset
2771 * and returns the one for the next entry after this directory block in
2775 nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
2776 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
2777 int *eofp, void *stuff)
2780 struct dirent *dp = NULL;
2782 nfsquad_t cookie, ncookie;
2783 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
2784 struct nfsnode *dnp = VTONFS(vp);
2785 struct nfsvattr nfsva;
2786 struct nfsrv_descript nfsd, *nd = &nfsd;
2787 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
2788 int reqsize, tryformoredirs = 1, readsize, eof = 0, gotmnton = 0;
2789 u_int64_t dotfileid, dotdotfileid = 0, fakefileno = UINT64_MAX;
2791 nfsattrbit_t attrbits, dattrbits;
2792 u_int32_t rderr, *tl2 = NULL;
2795 KASSERT(uiop->uio_iovcnt == 1 &&
2796 (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0,
2797 ("nfs readdirrpc bad uio"));
2800 * There is no point in reading a lot more than uio_resid, however
2801 * adding one additional DIRBLKSIZ makes sense. Since uio_resid
2802 * and nm_readdirsize are both exact multiples of DIRBLKSIZ, this
2803 * will never make readsize > nm_readdirsize.
2805 readsize = nmp->nm_readdirsize;
2806 if (readsize > uio_uio_resid(uiop))
2807 readsize = uio_uio_resid(uiop) + DIRBLKSIZ;
2812 tresid = uio_uio_resid(uiop);
2813 cookie.lval[0] = cookiep->nfsuquad[0];
2814 cookie.lval[1] = cookiep->nfsuquad[1];
2818 * For NFSv4, first create the "." and ".." entries.
2820 if (NFSHASNFSV4(nmp)) {
2821 reqsize = 6 * NFSX_UNSIGNED;
2822 NFSGETATTR_ATTRBIT(&dattrbits);
2823 NFSZERO_ATTRBIT(&attrbits);
2824 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID);
2825 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TYPE);
2826 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
2827 NFSATTRBIT_MOUNTEDONFILEID)) {
2828 NFSSETBIT_ATTRBIT(&attrbits,
2829 NFSATTRBIT_MOUNTEDONFILEID);
2833 * Must fake it. Use the fileno, except when the
2834 * fsid is != to that of the directory. For that
2835 * case, generate a fake fileno that is not the same.
2837 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID);
2842 * Joy, oh joy. For V4 we get to hand craft '.' and '..'.
2844 if (uiop->uio_offset == 0) {
2845 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp);
2846 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2847 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
2848 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2849 (void) nfsrv_putattrbit(nd, &attrbits);
2850 error = nfscl_request(nd, vp, p, cred, stuff);
2853 dotfileid = 0; /* Fake out the compiler. */
2854 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
2855 error = nfsm_loadattr(nd, &nfsva);
2858 dotfileid = nfsva.na_fileid;
2860 if (nd->nd_repstat == 0) {
2861 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2862 len = fxdr_unsigned(int, *(tl + 4));
2863 if (len > 0 && len <= NFSX_V4FHMAX)
2864 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
2868 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
2869 nfsva.na_mntonfileno = UINT64_MAX;
2870 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
2871 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
2872 NULL, NULL, NULL, p, cred);
2874 dotdotfileid = dotfileid;
2875 } else if (gotmnton) {
2876 if (nfsva.na_mntonfileno != UINT64_MAX)
2877 dotdotfileid = nfsva.na_mntonfileno;
2879 dotdotfileid = nfsva.na_fileid;
2880 } else if (nfsva.na_filesid[0] ==
2881 dnp->n_vattr.na_filesid[0] &&
2882 nfsva.na_filesid[1] ==
2883 dnp->n_vattr.na_filesid[1]) {
2884 dotdotfileid = nfsva.na_fileid;
2888 } while (fakefileno ==
2890 dotdotfileid = fakefileno;
2893 } else if (nd->nd_repstat == NFSERR_NOENT) {
2895 * Lookupp returns NFSERR_NOENT when we are
2896 * at the root, so just use the current dir.
2899 dotdotfileid = dotfileid;
2901 error = nd->nd_repstat;
2903 mbuf_freem(nd->nd_mrep);
2907 dp = (struct dirent *)uio_iov_base(uiop);
2909 dp->d_type = DT_DIR;
2910 dp->d_fileno = dotfileid;
2912 *((uint64_t *)dp->d_name) = 0; /* Zero pad it. */
2913 dp->d_name[0] = '.';
2914 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER;
2916 * Just make these offset cookie 0.
2918 tl = (u_int32_t *)&dp->d_name[8];
2921 blksiz += dp->d_reclen;
2922 uio_uio_resid_add(uiop, -(dp->d_reclen));
2923 uiop->uio_offset += dp->d_reclen;
2924 uio_iov_base_add(uiop, dp->d_reclen);
2925 uio_iov_len_add(uiop, -(dp->d_reclen));
2926 dp = (struct dirent *)uio_iov_base(uiop);
2928 dp->d_type = DT_DIR;
2929 dp->d_fileno = dotdotfileid;
2931 *((uint64_t *)dp->d_name) = 0;
2932 dp->d_name[0] = '.';
2933 dp->d_name[1] = '.';
2934 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER;
2936 * Just make these offset cookie 0.
2938 tl = (u_int32_t *)&dp->d_name[8];
2941 blksiz += dp->d_reclen;
2942 uio_uio_resid_add(uiop, -(dp->d_reclen));
2943 uiop->uio_offset += dp->d_reclen;
2944 uio_iov_base_add(uiop, dp->d_reclen);
2945 uio_iov_len_add(uiop, -(dp->d_reclen));
2947 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_RDATTRERROR);
2949 reqsize = 5 * NFSX_UNSIGNED;
2954 * Loop around doing readdir rpc's of size readsize.
2955 * The stopping criteria is EOF or buffer full.
2957 while (more_dirs && bigenough) {
2959 NFSCL_REQSTART(nd, NFSPROC_READDIR, vp);
2960 if (nd->nd_flag & ND_NFSV2) {
2961 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2962 *tl++ = cookie.lval[1];
2963 *tl = txdr_unsigned(readsize);
2965 NFSM_BUILD(tl, u_int32_t *, reqsize);
2966 *tl++ = cookie.lval[0];
2967 *tl++ = cookie.lval[1];
2968 if (cookie.qval == 0) {
2973 *tl++ = dnp->n_cookieverf.nfsuquad[0];
2974 *tl++ = dnp->n_cookieverf.nfsuquad[1];
2977 if (nd->nd_flag & ND_NFSV4) {
2978 *tl++ = txdr_unsigned(readsize);
2979 *tl = txdr_unsigned(readsize);
2980 (void) nfsrv_putattrbit(nd, &attrbits);
2981 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2982 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2983 (void) nfsrv_putattrbit(nd, &dattrbits);
2985 *tl = txdr_unsigned(readsize);
2988 error = nfscl_request(nd, vp, p, cred, stuff);
2991 if (!(nd->nd_flag & ND_NFSV2)) {
2992 if (nd->nd_flag & ND_NFSV3)
2993 error = nfscl_postop_attr(nd, nap, attrflagp,
2995 if (!nd->nd_repstat && !error) {
2996 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2998 dnp->n_cookieverf.nfsuquad[0] = *tl++;
2999 dnp->n_cookieverf.nfsuquad[1] = *tl;
3003 if (nd->nd_repstat || error) {
3005 error = nd->nd_repstat;
3008 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3009 more_dirs = fxdr_unsigned(int, *tl);
3013 /* loop through the dir entries, doctoring them to 4bsd form */
3014 while (more_dirs && bigenough) {
3015 if (nd->nd_flag & ND_NFSV4) {
3016 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3017 ncookie.lval[0] = *tl++;
3018 ncookie.lval[1] = *tl++;
3019 len = fxdr_unsigned(int, *tl);
3020 } else if (nd->nd_flag & ND_NFSV3) {
3021 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3022 nfsva.na_fileid = fxdr_hyper(tl);
3024 len = fxdr_unsigned(int, *tl);
3026 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
3027 nfsva.na_fileid = fxdr_unsigned(uint64_t,
3029 len = fxdr_unsigned(int, *tl);
3031 if (len <= 0 || len > NFS_MAXNAMLEN) {
3035 tlen = roundup2(len, 8);
3037 tlen += 8; /* To ensure null termination. */
3038 left = DIRBLKSIZ - blksiz;
3039 if (_GENERIC_DIRLEN(len) + NFSX_HYPER > left) {
3040 dp->d_reclen += left;
3041 uio_iov_base_add(uiop, left);
3042 uio_iov_len_add(uiop, -(left));
3043 uio_uio_resid_add(uiop, -(left));
3044 uiop->uio_offset += left;
3047 if (_GENERIC_DIRLEN(len) + NFSX_HYPER >
3048 uio_uio_resid(uiop))
3051 dp = (struct dirent *)uio_iov_base(uiop);
3054 dp->d_reclen = _GENERIC_DIRLEN(len) +
3056 dp->d_type = DT_UNKNOWN;
3057 blksiz += dp->d_reclen;
3058 if (blksiz == DIRBLKSIZ)
3060 uio_uio_resid_add(uiop, -(DIRHDSIZ));
3061 uiop->uio_offset += DIRHDSIZ;
3062 uio_iov_base_add(uiop, DIRHDSIZ);
3063 uio_iov_len_add(uiop, -(DIRHDSIZ));
3064 error = nfsm_mbufuio(nd, uiop, len);
3067 cp = uio_iov_base(uiop);
3069 *cp = '\0'; /* null terminate */
3070 cp += tlen; /* points to cookie storage */
3071 tl2 = (u_int32_t *)cp;
3072 uio_iov_base_add(uiop, (tlen + NFSX_HYPER));
3073 uio_iov_len_add(uiop, -(tlen + NFSX_HYPER));
3074 uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER));
3075 uiop->uio_offset += (tlen + NFSX_HYPER);
3077 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
3081 if (nd->nd_flag & ND_NFSV4) {
3083 nfsva.na_mntonfileno = UINT64_MAX;
3084 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
3085 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
3086 NULL, NULL, &rderr, p, cred);
3089 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3090 } else if (nd->nd_flag & ND_NFSV3) {
3091 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3092 ncookie.lval[0] = *tl++;
3093 ncookie.lval[1] = *tl++;
3095 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
3096 ncookie.lval[0] = 0;
3097 ncookie.lval[1] = *tl++;
3100 if (nd->nd_flag & ND_NFSV4) {
3105 if (nfsva.na_mntonfileno != UINT64_MAX)
3106 dp->d_fileno = nfsva.na_mntonfileno;
3108 dp->d_fileno = nfsva.na_fileid;
3109 } else if (nfsva.na_filesid[0] ==
3110 dnp->n_vattr.na_filesid[0] &&
3111 nfsva.na_filesid[1] ==
3112 dnp->n_vattr.na_filesid[1]) {
3113 dp->d_fileno = nfsva.na_fileid;
3117 } while (fakefileno ==
3119 dp->d_fileno = fakefileno;
3121 dp->d_type = vtonfs_dtype(nfsva.na_type);
3124 dp->d_fileno = nfsva.na_fileid;
3126 *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] =
3128 *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] =
3131 more_dirs = fxdr_unsigned(int, *tl);
3134 * If at end of rpc data, get the eof boolean
3137 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3138 eof = fxdr_unsigned(int, *tl);
3141 if (nd->nd_flag & ND_NFSV4) {
3142 error = nfscl_postop_attr(nd, nap, attrflagp,
3148 mbuf_freem(nd->nd_mrep);
3152 * Fill last record, iff any, out to a multiple of DIRBLKSIZ
3153 * by increasing d_reclen for the last record.
3156 left = DIRBLKSIZ - blksiz;
3157 dp->d_reclen += left;
3158 uio_iov_base_add(uiop, left);
3159 uio_iov_len_add(uiop, -(left));
3160 uio_uio_resid_add(uiop, -(left));
3161 uiop->uio_offset += left;
3165 * If returning no data, assume end of file.
3166 * If not bigenough, return not end of file, since you aren't
3167 * returning all the data
3168 * Otherwise, return the eof flag from the server.
3171 if (tresid == ((size_t)(uio_uio_resid(uiop))))
3173 else if (!bigenough)
3180 * Add extra empty records to any remaining DIRBLKSIZ chunks.
3182 while (uio_uio_resid(uiop) > 0 && uio_uio_resid(uiop) != tresid) {
3183 dp = (struct dirent *)uio_iov_base(uiop);
3184 dp->d_type = DT_UNKNOWN;
3187 dp->d_name[0] = '\0';
3188 tl = (u_int32_t *)&dp->d_name[4];
3189 *tl++ = cookie.lval[0];
3190 *tl = cookie.lval[1];
3191 dp->d_reclen = DIRBLKSIZ;
3192 uio_iov_base_add(uiop, DIRBLKSIZ);
3193 uio_iov_len_add(uiop, -(DIRBLKSIZ));
3194 uio_uio_resid_add(uiop, -(DIRBLKSIZ));
3195 uiop->uio_offset += DIRBLKSIZ;
3199 if (nd->nd_mrep != NULL)
3200 mbuf_freem(nd->nd_mrep);
3206 * NFS V3 readdir plus RPC. Used in place of nfsrpc_readdir().
3207 * (Also used for NFS V4 when mount flag set.)
3208 * (ditto above w.r.t. multiple of DIRBLKSIZ, etc.)
3211 nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
3212 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
3213 int *eofp, void *stuff)
3216 struct dirent *dp = NULL;
3218 vnode_t newvp = NULLVP;
3219 struct nfsrv_descript nfsd, *nd = &nfsd;
3220 struct nameidata nami, *ndp = &nami;
3221 struct componentname *cnp = &ndp->ni_cnd;
3222 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
3223 struct nfsnode *dnp = VTONFS(vp), *np;
3224 struct nfsvattr nfsva;
3226 nfsquad_t cookie, ncookie;
3227 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
3228 int attrflag, tryformoredirs = 1, eof = 0, gotmnton = 0;
3229 int isdotdot = 0, unlocknewvp = 0;
3230 u_int64_t dotfileid, dotdotfileid = 0, fakefileno = UINT64_MAX;
3231 u_int64_t fileno = 0;
3233 nfsattrbit_t attrbits, dattrbits;
3235 u_int32_t *tl2 = NULL, rderr;
3236 struct timespec dctime;
3238 KASSERT(uiop->uio_iovcnt == 1 &&
3239 (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0,
3240 ("nfs readdirplusrpc bad uio"));
3241 timespecclear(&dctime);
3247 cookie.lval[0] = cookiep->nfsuquad[0];
3248 cookie.lval[1] = cookiep->nfsuquad[1];
3249 tresid = uio_uio_resid(uiop);
3252 * For NFSv4, first create the "." and ".." entries.
3254 if (NFSHASNFSV4(nmp)) {
3255 NFSGETATTR_ATTRBIT(&dattrbits);
3256 NFSZERO_ATTRBIT(&attrbits);
3257 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID);
3258 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
3259 NFSATTRBIT_MOUNTEDONFILEID)) {
3260 NFSSETBIT_ATTRBIT(&attrbits,
3261 NFSATTRBIT_MOUNTEDONFILEID);
3265 * Must fake it. Use the fileno, except when the
3266 * fsid is != to that of the directory. For that
3267 * case, generate a fake fileno that is not the same.
3269 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID);
3274 * Joy, oh joy. For V4 we get to hand craft '.' and '..'.
3276 if (uiop->uio_offset == 0) {
3277 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp);
3278 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3279 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
3280 *tl = txdr_unsigned(NFSV4OP_GETATTR);
3281 (void) nfsrv_putattrbit(nd, &attrbits);
3282 error = nfscl_request(nd, vp, p, cred, stuff);
3285 dotfileid = 0; /* Fake out the compiler. */
3286 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
3287 error = nfsm_loadattr(nd, &nfsva);
3290 dctime = nfsva.na_ctime;
3291 dotfileid = nfsva.na_fileid;
3293 if (nd->nd_repstat == 0) {
3294 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
3295 len = fxdr_unsigned(int, *(tl + 4));
3296 if (len > 0 && len <= NFSX_V4FHMAX)
3297 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
3301 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
3302 nfsva.na_mntonfileno = UINT64_MAX;
3303 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
3304 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
3305 NULL, NULL, NULL, p, cred);
3307 dotdotfileid = dotfileid;
3308 } else if (gotmnton) {
3309 if (nfsva.na_mntonfileno != UINT64_MAX)
3310 dotdotfileid = nfsva.na_mntonfileno;
3312 dotdotfileid = nfsva.na_fileid;
3313 } else if (nfsva.na_filesid[0] ==
3314 dnp->n_vattr.na_filesid[0] &&
3315 nfsva.na_filesid[1] ==
3316 dnp->n_vattr.na_filesid[1]) {
3317 dotdotfileid = nfsva.na_fileid;
3321 } while (fakefileno ==
3323 dotdotfileid = fakefileno;
3326 } else if (nd->nd_repstat == NFSERR_NOENT) {
3328 * Lookupp returns NFSERR_NOENT when we are
3329 * at the root, so just use the current dir.
3332 dotdotfileid = dotfileid;
3334 error = nd->nd_repstat;
3336 mbuf_freem(nd->nd_mrep);
3340 dp = (struct dirent *)uio_iov_base(uiop);
3342 dp->d_type = DT_DIR;
3343 dp->d_fileno = dotfileid;
3345 *((uint64_t *)dp->d_name) = 0; /* Zero pad it. */
3346 dp->d_name[0] = '.';
3347 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER;
3349 * Just make these offset cookie 0.
3351 tl = (u_int32_t *)&dp->d_name[8];
3354 blksiz += dp->d_reclen;
3355 uio_uio_resid_add(uiop, -(dp->d_reclen));
3356 uiop->uio_offset += dp->d_reclen;
3357 uio_iov_base_add(uiop, dp->d_reclen);
3358 uio_iov_len_add(uiop, -(dp->d_reclen));
3359 dp = (struct dirent *)uio_iov_base(uiop);
3361 dp->d_type = DT_DIR;
3362 dp->d_fileno = dotdotfileid;
3364 *((uint64_t *)dp->d_name) = 0;
3365 dp->d_name[0] = '.';
3366 dp->d_name[1] = '.';
3367 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER;
3369 * Just make these offset cookie 0.
3371 tl = (u_int32_t *)&dp->d_name[8];
3374 blksiz += dp->d_reclen;
3375 uio_uio_resid_add(uiop, -(dp->d_reclen));
3376 uiop->uio_offset += dp->d_reclen;
3377 uio_iov_base_add(uiop, dp->d_reclen);
3378 uio_iov_len_add(uiop, -(dp->d_reclen));
3380 NFSREADDIRPLUS_ATTRBIT(&attrbits);
3382 NFSSETBIT_ATTRBIT(&attrbits,
3383 NFSATTRBIT_MOUNTEDONFILEID);
3387 * Loop around doing readdir rpc's of size nm_readdirsize.
3388 * The stopping criteria is EOF or buffer full.
3390 while (more_dirs && bigenough) {
3392 NFSCL_REQSTART(nd, NFSPROC_READDIRPLUS, vp);
3393 NFSM_BUILD(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
3394 *tl++ = cookie.lval[0];
3395 *tl++ = cookie.lval[1];
3396 if (cookie.qval == 0) {
3401 *tl++ = dnp->n_cookieverf.nfsuquad[0];
3402 *tl++ = dnp->n_cookieverf.nfsuquad[1];
3405 *tl++ = txdr_unsigned(nmp->nm_readdirsize);
3406 *tl = txdr_unsigned(nmp->nm_readdirsize);
3407 if (nd->nd_flag & ND_NFSV4) {
3408 (void) nfsrv_putattrbit(nd, &attrbits);
3409 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3410 *tl = txdr_unsigned(NFSV4OP_GETATTR);
3411 (void) nfsrv_putattrbit(nd, &dattrbits);
3413 error = nfscl_request(nd, vp, p, cred, stuff);
3416 if (nd->nd_flag & ND_NFSV3)
3417 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3418 if (nd->nd_repstat || error) {
3420 error = nd->nd_repstat;
3423 if ((nd->nd_flag & ND_NFSV3) != 0 && *attrflagp != 0)
3424 dctime = nap->na_ctime;
3425 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3427 dnp->n_cookieverf.nfsuquad[0] = *tl++;
3428 dnp->n_cookieverf.nfsuquad[1] = *tl++;
3430 more_dirs = fxdr_unsigned(int, *tl);
3434 /* loop through the dir entries, doctoring them to 4bsd form */
3435 while (more_dirs && bigenough) {
3436 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3437 if (nd->nd_flag & ND_NFSV4) {
3438 ncookie.lval[0] = *tl++;
3439 ncookie.lval[1] = *tl++;
3441 fileno = fxdr_hyper(tl);
3444 len = fxdr_unsigned(int, *tl);
3445 if (len <= 0 || len > NFS_MAXNAMLEN) {
3449 tlen = roundup2(len, 8);
3451 tlen += 8; /* To ensure null termination. */
3452 left = DIRBLKSIZ - blksiz;
3453 if (_GENERIC_DIRLEN(len) + NFSX_HYPER > left) {
3454 dp->d_reclen += left;
3455 uio_iov_base_add(uiop, left);
3456 uio_iov_len_add(uiop, -(left));
3457 uio_uio_resid_add(uiop, -(left));
3458 uiop->uio_offset += left;
3461 if (_GENERIC_DIRLEN(len) + NFSX_HYPER >
3462 uio_uio_resid(uiop))
3465 dp = (struct dirent *)uio_iov_base(uiop);
3468 dp->d_reclen = _GENERIC_DIRLEN(len) +
3470 dp->d_type = DT_UNKNOWN;
3471 blksiz += dp->d_reclen;
3472 if (blksiz == DIRBLKSIZ)
3474 uio_uio_resid_add(uiop, -(DIRHDSIZ));
3475 uiop->uio_offset += DIRHDSIZ;
3476 uio_iov_base_add(uiop, DIRHDSIZ);
3477 uio_iov_len_add(uiop, -(DIRHDSIZ));
3478 cnp->cn_nameptr = uio_iov_base(uiop);
3479 cnp->cn_namelen = len;
3481 error = nfsm_mbufuio(nd, uiop, len);
3484 cp = uio_iov_base(uiop);
3487 cp += tlen; /* points to cookie storage */
3488 tl2 = (u_int32_t *)cp;
3489 if (len == 2 && cnp->cn_nameptr[0] == '.' &&
3490 cnp->cn_nameptr[1] == '.')
3494 uio_iov_base_add(uiop, (tlen + NFSX_HYPER));
3495 uio_iov_len_add(uiop, -(tlen + NFSX_HYPER));
3496 uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER));
3497 uiop->uio_offset += (tlen + NFSX_HYPER);
3499 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
3504 if (nd->nd_flag & ND_NFSV3) {
3505 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3506 ncookie.lval[0] = *tl++;
3507 ncookie.lval[1] = *tl++;
3508 attrflag = fxdr_unsigned(int, *tl);
3510 error = nfsm_loadattr(nd, &nfsva);
3514 NFSM_DISSECT(tl,u_int32_t *,NFSX_UNSIGNED);
3516 error = nfsm_getfh(nd, &nfhp);
3520 if (!attrflag && nfhp != NULL) {
3521 FREE((caddr_t)nfhp, M_NFSFH);
3526 nfsva.na_mntonfileno = 0xffffffff;
3527 error = nfsv4_loadattr(nd, NULL, &nfsva, &nfhp,
3528 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
3529 NULL, NULL, &rderr, p, cred);
3535 if (nd->nd_flag & ND_NFSV4) {
3538 } else if (gotmnton) {
3539 if (nfsva.na_mntonfileno != 0xffffffff)
3540 dp->d_fileno = nfsva.na_mntonfileno;
3542 dp->d_fileno = nfsva.na_fileid;
3543 } else if (nfsva.na_filesid[0] ==
3544 dnp->n_vattr.na_filesid[0] &&
3545 nfsva.na_filesid[1] ==
3546 dnp->n_vattr.na_filesid[1]) {
3547 dp->d_fileno = nfsva.na_fileid;
3551 } while (fakefileno ==
3553 dp->d_fileno = fakefileno;
3556 dp->d_fileno = fileno;
3558 *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] =
3560 *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] =
3564 if (NFSRV_CMPFH(nfhp->nfh_fh, nfhp->nfh_len,
3565 dnp->n_fhp->nfh_fh, dnp->n_fhp->nfh_len)) {
3569 FREE((caddr_t)nfhp, M_NFSFH);
3571 } else if (isdotdot != 0) {
3573 * Skip doing a nfscl_nget() call for "..".
3574 * There's a race between acquiring the nfs
3575 * node here and lookups that look for the
3576 * directory being read (in the parent).
3577 * It would try to get a lock on ".." here,
3578 * owning the lock on the directory being
3579 * read. Lookup will hold the lock on ".."
3580 * and try to acquire the lock on the
3581 * directory being read.
3582 * If the directory is unlocked/relocked,
3583 * then there is a LOR with the buflock
3586 free(nfhp, M_NFSFH);
3588 error = nfscl_nget(vnode_mount(vp), vp,
3589 nfhp, cnp, p, &np, NULL, LK_EXCLUSIVE);
3596 if (newvp != NULLVP) {
3597 error = nfscl_loadattrcache(&newvp,
3598 &nfsva, NULL, NULL, 0, 0);
3607 vtonfs_dtype(np->n_vattr.na_type);
3609 NFSCNHASH(cnp, HASHINIT);
3610 if (cnp->cn_namelen <= NCHNAMLEN &&
3611 (newvp->v_type != VDIR ||
3612 dctime.tv_sec != 0)) {
3613 cache_enter_time(ndp->ni_dvp,
3616 newvp->v_type != VDIR ? NULL :
3626 } else if (nfhp != NULL) {
3627 FREE((caddr_t)nfhp, M_NFSFH);
3629 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3630 more_dirs = fxdr_unsigned(int, *tl);
3633 * If at end of rpc data, get the eof boolean
3636 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3637 eof = fxdr_unsigned(int, *tl);
3640 if (nd->nd_flag & ND_NFSV4) {
3641 error = nfscl_postop_attr(nd, nap, attrflagp,
3647 mbuf_freem(nd->nd_mrep);
3651 * Fill last record, iff any, out to a multiple of DIRBLKSIZ
3652 * by increasing d_reclen for the last record.
3655 left = DIRBLKSIZ - blksiz;
3656 dp->d_reclen += left;
3657 uio_iov_base_add(uiop, left);
3658 uio_iov_len_add(uiop, -(left));
3659 uio_uio_resid_add(uiop, -(left));
3660 uiop->uio_offset += left;
3664 * If returning no data, assume end of file.
3665 * If not bigenough, return not end of file, since you aren't
3666 * returning all the data
3667 * Otherwise, return the eof flag from the server.
3670 if (tresid == uio_uio_resid(uiop))
3672 else if (!bigenough)
3679 * Add extra empty records to any remaining DIRBLKSIZ chunks.
3681 while (uio_uio_resid(uiop) > 0 && uio_uio_resid(uiop) != tresid) {
3682 dp = (struct dirent *)uio_iov_base(uiop);
3683 dp->d_type = DT_UNKNOWN;
3686 dp->d_name[0] = '\0';
3687 tl = (u_int32_t *)&dp->d_name[4];
3688 *tl++ = cookie.lval[0];
3689 *tl = cookie.lval[1];
3690 dp->d_reclen = DIRBLKSIZ;
3691 uio_iov_base_add(uiop, DIRBLKSIZ);
3692 uio_iov_len_add(uiop, -(DIRBLKSIZ));
3693 uio_uio_resid_add(uiop, -(DIRBLKSIZ));
3694 uiop->uio_offset += DIRBLKSIZ;
3698 if (nd->nd_mrep != NULL)
3699 mbuf_freem(nd->nd_mrep);
3708 nfsrpc_commit(vnode_t vp, u_quad_t offset, int cnt, struct ucred *cred,
3709 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
3712 struct nfsrv_descript nfsd, *nd = &nfsd;
3713 nfsattrbit_t attrbits;
3715 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
3718 NFSCL_REQSTART(nd, NFSPROC_COMMIT, vp);
3719 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3720 txdr_hyper(offset, tl);
3722 *tl = txdr_unsigned(cnt);
3723 if (nd->nd_flag & ND_NFSV4) {
3725 * And do a Getattr op.
3727 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3728 *tl = txdr_unsigned(NFSV4OP_GETATTR);
3729 NFSGETATTR_ATTRBIT(&attrbits);
3730 (void) nfsrv_putattrbit(nd, &attrbits);
3732 error = nfscl_request(nd, vp, p, cred, stuff);
3735 error = nfscl_wcc_data(nd, vp, nap, attrflagp, NULL, stuff);
3736 if (!error && !nd->nd_repstat) {
3737 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
3739 if (NFSBCMP(nmp->nm_verf, tl, NFSX_VERF)) {
3740 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
3741 nd->nd_repstat = NFSERR_STALEWRITEVERF;
3744 if (nd->nd_flag & ND_NFSV4)
3745 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3748 if (!error && nd->nd_repstat)
3749 error = nd->nd_repstat;
3750 mbuf_freem(nd->nd_mrep);
3755 * NFS byte range lock rpc.
3756 * (Mostly just calls one of the three lower level RPC routines.)
3759 nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
3760 int reclaim, struct ucred *cred, NFSPROC_T *p, void *id, int flags)
3762 struct nfscllockowner *lp;
3763 struct nfsclclient *clp;
3765 struct nfsrv_descript nfsd, *nd = &nfsd;
3766 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
3769 u_int32_t clidrev = 0;
3770 int error = 0, newone = 0, expireret = 0, retrycnt, donelocally;
3774 * Convert the flock structure into a start and end and do POSIX
3777 switch (fl->l_whence) {
3781 * Caller is responsible for adding any necessary offset
3782 * when SEEK_CUR is used.
3784 start = fl->l_start;
3788 start = size + fl->l_start;
3789 off = size + fl->l_start;
3796 if (fl->l_len != 0) {
3797 end = start + fl->l_len - 1;
3808 if (op == F_GETLK) {
3809 error = nfscl_getcl(vnode_mount(vp), cred, p, 1, &clp);
3812 error = nfscl_lockt(vp, clp, off, len, fl, p, id, flags);
3814 clidrev = clp->nfsc_clientidrev;
3815 error = nfsrpc_lockt(nd, vp, clp, off, len, fl, cred,
3817 } else if (error == -1) {
3820 nfscl_clientrelease(clp);
3821 } else if (op == F_UNLCK && fl->l_type == F_UNLCK) {
3823 * We must loop around for all lockowner cases.
3826 error = nfscl_getcl(vnode_mount(vp), cred, p, 1, &clp);
3830 error = nfscl_relbytelock(vp, off, len, cred, p, callcnt,
3831 clp, id, flags, &lp, &dorpc);
3833 * If it returns a NULL lp, we're done.
3837 nfscl_clientrelease(clp);
3839 nfscl_releasealllocks(clp, vp, p, id, flags);
3842 if (nmp->nm_clp != NULL)
3843 clidrev = nmp->nm_clp->nfsc_clientidrev;
3847 * If the server doesn't support Posix lock semantics,
3848 * only allow locks on the entire file, since it won't
3849 * handle overlapping byte ranges.
3850 * There might still be a problem when a lock
3851 * upgrade/downgrade (read<->write) occurs, since the
3852 * server "might" expect an unlock first?
3854 if (dorpc && (lp->nfsl_open->nfso_posixlock ||
3855 (off == 0 && len == NFS64BITSSET))) {
3857 * Since the lock records will go away, we must
3858 * wait for grace and delay here.
3861 error = nfsrpc_locku(nd, nmp, lp, off, len,
3862 NFSV4LOCKT_READ, cred, p, 0);
3863 if ((nd->nd_repstat == NFSERR_GRACE ||
3864 nd->nd_repstat == NFSERR_DELAY) &&
3866 (void) nfs_catnap(PZERO, (int)nd->nd_repstat,
3868 } while ((nd->nd_repstat == NFSERR_GRACE ||
3869 nd->nd_repstat == NFSERR_DELAY) && error == 0);
3872 } while (error == 0 && nd->nd_repstat == 0);
3873 nfscl_releasealllocks(clp, vp, p, id, flags);
3874 } else if (op == F_SETLK) {
3875 error = nfscl_getbytelock(vp, off, len, fl->l_type, cred, p,
3876 NULL, 0, id, flags, NULL, NULL, &lp, &newone, &donelocally);
3877 if (error || donelocally) {
3880 if (nmp->nm_clp != NULL)
3881 clidrev = nmp->nm_clp->nfsc_clientidrev;
3884 nfhp = VTONFS(vp)->n_fhp;
3885 if (!lp->nfsl_open->nfso_posixlock &&
3886 (off != 0 || len != NFS64BITSSET)) {
3889 error = nfsrpc_lock(nd, nmp, vp, nfhp->nfh_fh,
3890 nfhp->nfh_len, lp, newone, reclaim, off,
3891 len, fl->l_type, cred, p, 0);
3894 error = nd->nd_repstat;
3895 nfscl_lockrelease(lp, error, newone);
3900 error = nd->nd_repstat;
3901 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
3902 error == NFSERR_STALEDONTRECOVER ||
3903 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY ||
3904 error == NFSERR_BADSESSION) {
3905 (void) nfs_catnap(PZERO, error, "nfs_advlock");
3906 } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID)
3908 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
3911 } while (error == NFSERR_GRACE ||
3912 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY ||
3913 error == NFSERR_STALEDONTRECOVER || error == NFSERR_STALESTATEID ||
3914 error == NFSERR_BADSESSION ||
3915 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
3916 expireret == 0 && clidrev != 0 && retrycnt < 4));
3917 if (error && retrycnt >= 4)
3923 * The lower level routine for the LockT case.
3926 nfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp,
3927 struct nfsclclient *clp, u_int64_t off, u_int64_t len, struct flock *fl,
3928 struct ucred *cred, NFSPROC_T *p, void *id, int flags)
3931 int error, type, size;
3932 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
3934 struct nfsmount *nmp;
3935 struct nfsclsession *tsep;
3937 nmp = VFSTONFS(vp->v_mount);
3938 NFSCL_REQSTART(nd, NFSPROC_LOCKT, vp);
3939 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
3940 if (fl->l_type == F_RDLCK)
3941 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
3943 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
3944 txdr_hyper(off, tl);
3946 txdr_hyper(len, tl);
3948 tsep = nfsmnt_mdssession(nmp);
3949 *tl++ = tsep->nfsess_clientid.lval[0];
3950 *tl = tsep->nfsess_clientid.lval[1];
3951 nfscl_filllockowner(id, own, flags);
3953 NFSBCOPY(np->n_fhp->nfh_fh, &own[NFSV4CL_LOCKNAMELEN],
3954 np->n_fhp->nfh_len);
3955 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + np->n_fhp->nfh_len);
3956 error = nfscl_request(nd, vp, p, cred, NULL);
3959 if (nd->nd_repstat == 0) {
3960 fl->l_type = F_UNLCK;
3961 } else if (nd->nd_repstat == NFSERR_DENIED) {
3963 fl->l_whence = SEEK_SET;
3964 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
3965 fl->l_start = fxdr_hyper(tl);
3967 len = fxdr_hyper(tl);
3969 if (len == NFS64BITSSET)
3973 type = fxdr_unsigned(int, *tl++);
3974 if (type == NFSV4LOCKT_WRITE)
3975 fl->l_type = F_WRLCK;
3977 fl->l_type = F_RDLCK;
3979 * XXX For now, I have no idea what to do with the
3980 * conflicting lock_owner, so I'll just set the pid == 0
3981 * and skip over the lock_owner.
3983 fl->l_pid = (pid_t)0;
3985 size = fxdr_unsigned(int, *tl);
3986 if (size < 0 || size > NFSV4_OPAQUELIMIT)
3989 error = nfsm_advance(nd, NFSM_RNDUP(size), -1);
3990 } else if (nd->nd_repstat == NFSERR_STALECLIENTID)
3991 nfscl_initiate_recovery(clp);
3993 mbuf_freem(nd->nd_mrep);
3998 * Lower level function that performs the LockU RPC.
4001 nfsrpc_locku(struct nfsrv_descript *nd, struct nfsmount *nmp,
4002 struct nfscllockowner *lp, u_int64_t off, u_int64_t len,
4003 u_int32_t type, struct ucred *cred, NFSPROC_T *p, int syscred)
4008 nfscl_reqstart(nd, NFSPROC_LOCKU, nmp, lp->nfsl_open->nfso_fh,
4009 lp->nfsl_open->nfso_fhlen, NULL, NULL);
4010 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
4011 *tl++ = txdr_unsigned(type);
4012 *tl = txdr_unsigned(lp->nfsl_seqid);
4013 if (nfstest_outofseq &&
4014 (arc4random() % nfstest_outofseq) == 0)
4015 *tl = txdr_unsigned(lp->nfsl_seqid + 1);
4017 if (NFSHASNFSV4N(nmp))
4020 *tl++ = lp->nfsl_stateid.seqid;
4021 *tl++ = lp->nfsl_stateid.other[0];
4022 *tl++ = lp->nfsl_stateid.other[1];
4023 *tl++ = lp->nfsl_stateid.other[2];
4024 txdr_hyper(off, tl);
4026 txdr_hyper(len, tl);
4028 nd->nd_flag |= ND_USEGSSNAME;
4029 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4030 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4031 NFSCL_INCRSEQID(lp->nfsl_seqid, nd);
4034 if (nd->nd_repstat == 0) {
4035 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
4036 lp->nfsl_stateid.seqid = *tl++;
4037 lp->nfsl_stateid.other[0] = *tl++;
4038 lp->nfsl_stateid.other[1] = *tl++;
4039 lp->nfsl_stateid.other[2] = *tl;
4040 } else if (nd->nd_repstat == NFSERR_STALESTATEID)
4041 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp);
4043 mbuf_freem(nd->nd_mrep);
4048 * The actual Lock RPC.
4051 nfsrpc_lock(struct nfsrv_descript *nd, struct nfsmount *nmp, vnode_t vp,
4052 u_int8_t *nfhp, int fhlen, struct nfscllockowner *lp, int newone,
4053 int reclaim, u_int64_t off, u_int64_t len, short type, struct ucred *cred,
4054 NFSPROC_T *p, int syscred)
4058 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
4059 struct nfsclsession *tsep;
4061 nfscl_reqstart(nd, NFSPROC_LOCK, nmp, nfhp, fhlen, NULL, NULL);
4062 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
4063 if (type == F_RDLCK)
4064 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
4066 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
4067 *tl++ = txdr_unsigned(reclaim);
4068 txdr_hyper(off, tl);
4070 txdr_hyper(len, tl);
4074 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID +
4075 2 * NFSX_UNSIGNED + NFSX_HYPER);
4076 *tl++ = txdr_unsigned(lp->nfsl_open->nfso_own->nfsow_seqid);
4077 if (NFSHASNFSV4N(nmp))
4080 *tl++ = lp->nfsl_open->nfso_stateid.seqid;
4081 *tl++ = lp->nfsl_open->nfso_stateid.other[0];
4082 *tl++ = lp->nfsl_open->nfso_stateid.other[1];
4083 *tl++ = lp->nfsl_open->nfso_stateid.other[2];
4084 *tl++ = txdr_unsigned(lp->nfsl_seqid);
4085 tsep = nfsmnt_mdssession(nmp);
4086 *tl++ = tsep->nfsess_clientid.lval[0];
4087 *tl = tsep->nfsess_clientid.lval[1];
4088 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN);
4089 NFSBCOPY(nfhp, &own[NFSV4CL_LOCKNAMELEN], fhlen);
4090 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen);
4093 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
4094 if (NFSHASNFSV4N(nmp))
4097 *tl++ = lp->nfsl_stateid.seqid;
4098 *tl++ = lp->nfsl_stateid.other[0];
4099 *tl++ = lp->nfsl_stateid.other[1];
4100 *tl++ = lp->nfsl_stateid.other[2];
4101 *tl = txdr_unsigned(lp->nfsl_seqid);
4102 if (nfstest_outofseq &&
4103 (arc4random() % nfstest_outofseq) == 0)
4104 *tl = txdr_unsigned(lp->nfsl_seqid + 1);
4107 nd->nd_flag |= ND_USEGSSNAME;
4108 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
4109 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4113 NFSCL_INCRSEQID(lp->nfsl_open->nfso_own->nfsow_seqid, nd);
4114 NFSCL_INCRSEQID(lp->nfsl_seqid, nd);
4115 if (nd->nd_repstat == 0) {
4116 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
4117 lp->nfsl_stateid.seqid = *tl++;
4118 lp->nfsl_stateid.other[0] = *tl++;
4119 lp->nfsl_stateid.other[1] = *tl++;
4120 lp->nfsl_stateid.other[2] = *tl;
4121 } else if (nd->nd_repstat == NFSERR_DENIED) {
4122 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
4123 size = fxdr_unsigned(int, *(tl + 7));
4124 if (size < 0 || size > NFSV4_OPAQUELIMIT)
4127 error = nfsm_advance(nd, NFSM_RNDUP(size), -1);
4128 } else if (nd->nd_repstat == NFSERR_STALESTATEID)
4129 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp);
4131 mbuf_freem(nd->nd_mrep);
4137 * (always called with the vp for the mount point)
4140 nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp,
4141 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
4144 u_int32_t *tl = NULL;
4145 struct nfsrv_descript nfsd, *nd = &nfsd;
4146 struct nfsmount *nmp;
4147 nfsattrbit_t attrbits;
4151 nmp = VFSTONFS(vnode_mount(vp));
4152 if (NFSHASNFSV4(nmp)) {
4154 * For V4, you actually do a getattr.
4156 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
4157 NFSSTATFS_GETATTRBIT(&attrbits);
4158 (void) nfsrv_putattrbit(nd, &attrbits);
4159 nd->nd_flag |= ND_USEGSSNAME;
4160 error = nfscl_request(nd, vp, p, cred, stuff);
4163 if (nd->nd_repstat == 0) {
4164 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
4165 NULL, NULL, sbp, fsp, NULL, 0, NULL, NULL, NULL, p,
4168 nmp->nm_fsid[0] = nap->na_filesid[0];
4169 nmp->nm_fsid[1] = nap->na_filesid[1];
4170 NFSSETHASSETFSID(nmp);
4174 error = nd->nd_repstat;
4179 NFSCL_REQSTART(nd, NFSPROC_FSSTAT, vp);
4180 error = nfscl_request(nd, vp, p, cred, stuff);
4183 if (nd->nd_flag & ND_NFSV3) {
4184 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
4188 if (nd->nd_repstat) {
4189 error = nd->nd_repstat;
4192 NFSM_DISSECT(tl, u_int32_t *,
4193 NFSX_STATFS(nd->nd_flag & ND_NFSV3));
4195 if (NFSHASNFSV3(nmp)) {
4196 sbp->sf_tbytes = fxdr_hyper(tl); tl += 2;
4197 sbp->sf_fbytes = fxdr_hyper(tl); tl += 2;
4198 sbp->sf_abytes = fxdr_hyper(tl); tl += 2;
4199 sbp->sf_tfiles = fxdr_hyper(tl); tl += 2;
4200 sbp->sf_ffiles = fxdr_hyper(tl); tl += 2;
4201 sbp->sf_afiles = fxdr_hyper(tl); tl += 2;
4202 sbp->sf_invarsec = fxdr_unsigned(u_int32_t, *tl);
4203 } else if (NFSHASNFSV4(nmp) == 0) {
4204 sbp->sf_tsize = fxdr_unsigned(u_int32_t, *tl++);
4205 sbp->sf_bsize = fxdr_unsigned(u_int32_t, *tl++);
4206 sbp->sf_blocks = fxdr_unsigned(u_int32_t, *tl++);
4207 sbp->sf_bfree = fxdr_unsigned(u_int32_t, *tl++);
4208 sbp->sf_bavail = fxdr_unsigned(u_int32_t, *tl);
4211 mbuf_freem(nd->nd_mrep);
4219 nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc,
4220 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
4223 struct nfsrv_descript nfsd, *nd = &nfsd;
4224 struct nfsmount *nmp;
4226 nfsattrbit_t attrbits;
4230 nmp = VFSTONFS(vnode_mount(vp));
4231 if (NFSHASNFSV4(nmp)) {
4233 * For V4, you actually do a getattr.
4235 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
4236 NFSPATHCONF_GETATTRBIT(&attrbits);
4237 (void) nfsrv_putattrbit(nd, &attrbits);
4238 nd->nd_flag |= ND_USEGSSNAME;
4239 error = nfscl_request(nd, vp, p, cred, stuff);
4242 if (nd->nd_repstat == 0) {
4243 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
4244 pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, p,
4249 error = nd->nd_repstat;
4252 NFSCL_REQSTART(nd, NFSPROC_PATHCONF, vp);
4253 error = nfscl_request(nd, vp, p, cred, stuff);
4256 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
4257 if (nd->nd_repstat && !error)
4258 error = nd->nd_repstat;
4260 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3PATHCONF);
4261 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl++);
4262 pc->pc_namemax = fxdr_unsigned(u_int32_t, *tl++);
4263 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl++);
4264 pc->pc_chownrestricted =
4265 fxdr_unsigned(u_int32_t, *tl++);
4266 pc->pc_caseinsensitive =
4267 fxdr_unsigned(u_int32_t, *tl++);
4268 pc->pc_casepreserving = fxdr_unsigned(u_int32_t, *tl);
4272 mbuf_freem(nd->nd_mrep);
4277 * nfs version 3 fsinfo rpc call
4280 nfsrpc_fsinfo(vnode_t vp, struct nfsfsinfo *fsp, struct ucred *cred,
4281 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
4284 struct nfsrv_descript nfsd, *nd = &nfsd;
4288 NFSCL_REQSTART(nd, NFSPROC_FSINFO, vp);
4289 error = nfscl_request(nd, vp, p, cred, stuff);
4292 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
4293 if (nd->nd_repstat && !error)
4294 error = nd->nd_repstat;
4296 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3FSINFO);
4297 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *tl++);
4298 fsp->fs_rtpref = fxdr_unsigned(u_int32_t, *tl++);
4299 fsp->fs_rtmult = fxdr_unsigned(u_int32_t, *tl++);
4300 fsp->fs_wtmax = fxdr_unsigned(u_int32_t, *tl++);
4301 fsp->fs_wtpref = fxdr_unsigned(u_int32_t, *tl++);
4302 fsp->fs_wtmult = fxdr_unsigned(u_int32_t, *tl++);
4303 fsp->fs_dtpref = fxdr_unsigned(u_int32_t, *tl++);
4304 fsp->fs_maxfilesize = fxdr_hyper(tl);
4306 fxdr_nfsv3time(tl, &fsp->fs_timedelta);
4308 fsp->fs_properties = fxdr_unsigned(u_int32_t, *tl);
4311 mbuf_freem(nd->nd_mrep);
4316 * This function performs the Renew RPC.
4319 nfsrpc_renew(struct nfsclclient *clp, struct nfsclds *dsp, struct ucred *cred,
4323 struct nfsrv_descript nfsd;
4324 struct nfsrv_descript *nd = &nfsd;
4325 struct nfsmount *nmp;
4327 struct nfssockreq *nrp;
4328 struct nfsclsession *tsep;
4330 nmp = clp->nfsc_nmp;
4334 nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL, NULL);
4336 nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL,
4337 &dsp->nfsclds_sess);
4338 if (!NFSHASNFSV4N(nmp)) {
4339 /* NFSv4.1 just uses a Sequence Op and not a Renew. */
4340 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4341 tsep = nfsmnt_mdssession(nmp);
4342 *tl++ = tsep->nfsess_clientid.lval[0];
4343 *tl = tsep->nfsess_clientid.lval[1];
4347 nrp = dsp->nfsclds_sockp;
4349 /* If NULL, use the MDS socket. */
4350 nrp = &nmp->nm_sockreq;
4351 nd->nd_flag |= ND_USEGSSNAME;
4353 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
4354 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4356 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
4357 NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
4360 error = nd->nd_repstat;
4361 mbuf_freem(nd->nd_mrep);
4366 * This function performs the Releaselockowner RPC.
4369 nfsrpc_rellockown(struct nfsmount *nmp, struct nfscllockowner *lp,
4370 uint8_t *fh, int fhlen, struct ucred *cred, NFSPROC_T *p)
4372 struct nfsrv_descript nfsd, *nd = &nfsd;
4375 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
4376 struct nfsclsession *tsep;
4378 if (NFSHASNFSV4N(nmp)) {
4379 /* For NFSv4.1, do a FreeStateID. */
4380 nfscl_reqstart(nd, NFSPROC_FREESTATEID, nmp, NULL, 0, NULL,
4382 nfsm_stateidtom(nd, &lp->nfsl_stateid, NFSSTATEID_PUTSTATEID);
4384 nfscl_reqstart(nd, NFSPROC_RELEASELCKOWN, nmp, NULL, 0, NULL,
4386 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4387 tsep = nfsmnt_mdssession(nmp);
4388 *tl++ = tsep->nfsess_clientid.lval[0];
4389 *tl = tsep->nfsess_clientid.lval[1];
4390 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN);
4391 NFSBCOPY(fh, &own[NFSV4CL_LOCKNAMELEN], fhlen);
4392 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen);
4394 nd->nd_flag |= ND_USEGSSNAME;
4395 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4396 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4399 error = nd->nd_repstat;
4400 mbuf_freem(nd->nd_mrep);
4405 * This function performs the Compound to get the mount pt FH.
4408 nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred,
4412 struct nfsrv_descript nfsd;
4413 struct nfsrv_descript *nd = &nfsd;
4415 int error, cnt, len, setnil;
4418 nfscl_reqstart(nd, NFSPROC_PUTROOTFH, nmp, NULL, 0, &opcntp, NULL);
4426 while (*cp2 != '\0' && *cp2 != '/')
4433 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4434 *tl = txdr_unsigned(NFSV4OP_LOOKUP);
4435 nfsm_strtom(nd, cp, strlen(cp));
4441 } while (*cp != '\0');
4442 if (NFSHASNFSV4N(nmp))
4443 /* Has a Sequence Op done by nfscl_reqstart(). */
4444 *opcntp = txdr_unsigned(3 + cnt);
4446 *opcntp = txdr_unsigned(2 + cnt);
4447 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4448 *tl = txdr_unsigned(NFSV4OP_GETFH);
4449 nd->nd_flag |= ND_USEGSSNAME;
4450 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4451 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4454 if (nd->nd_repstat == 0) {
4455 NFSM_DISSECT(tl, u_int32_t *, (3 + 2 * cnt) * NFSX_UNSIGNED);
4456 tl += (2 + 2 * cnt);
4457 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
4459 nd->nd_repstat = NFSERR_BADXDR;
4461 nd->nd_repstat = nfsrv_mtostr(nd, nmp->nm_fh, len);
4462 if (nd->nd_repstat == 0)
4463 nmp->nm_fhsize = len;
4466 error = nd->nd_repstat;
4468 mbuf_freem(nd->nd_mrep);
4473 * This function performs the Delegreturn RPC.
4476 nfsrpc_delegreturn(struct nfscldeleg *dp, struct ucred *cred,
4477 struct nfsmount *nmp, NFSPROC_T *p, int syscred)
4480 struct nfsrv_descript nfsd;
4481 struct nfsrv_descript *nd = &nfsd;
4484 nfscl_reqstart(nd, NFSPROC_DELEGRETURN, nmp, dp->nfsdl_fh,
4485 dp->nfsdl_fhlen, NULL, NULL);
4486 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
4487 if (NFSHASNFSV4N(nmp))
4490 *tl++ = dp->nfsdl_stateid.seqid;
4491 *tl++ = dp->nfsdl_stateid.other[0];
4492 *tl++ = dp->nfsdl_stateid.other[1];
4493 *tl = dp->nfsdl_stateid.other[2];
4495 nd->nd_flag |= ND_USEGSSNAME;
4496 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4497 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4500 error = nd->nd_repstat;
4501 mbuf_freem(nd->nd_mrep);
4509 nfsrpc_getacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
4510 struct acl *aclp, void *stuff)
4512 struct nfsrv_descript nfsd, *nd = &nfsd;
4514 nfsattrbit_t attrbits;
4515 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
4517 if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp))
4518 return (EOPNOTSUPP);
4519 NFSCL_REQSTART(nd, NFSPROC_GETACL, vp);
4520 NFSZERO_ATTRBIT(&attrbits);
4521 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
4522 (void) nfsrv_putattrbit(nd, &attrbits);
4523 error = nfscl_request(nd, vp, p, cred, stuff);
4526 if (!nd->nd_repstat)
4527 error = nfsv4_loadattr(nd, vp, NULL, NULL, NULL, 0, NULL,
4528 NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, p, cred);
4530 error = nd->nd_repstat;
4531 mbuf_freem(nd->nd_mrep);
4539 nfsrpc_setacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
4540 struct acl *aclp, void *stuff)
4543 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
4545 if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp))
4546 return (EOPNOTSUPP);
4547 error = nfsrpc_setattr(vp, NULL, aclp, cred, p, NULL, NULL, stuff);
4555 nfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
4556 struct acl *aclp, nfsv4stateid_t *stateidp, void *stuff)
4558 struct nfsrv_descript nfsd, *nd = &nfsd;
4560 nfsattrbit_t attrbits;
4561 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
4563 if (!NFSHASNFSV4(nmp))
4564 return (EOPNOTSUPP);
4565 NFSCL_REQSTART(nd, NFSPROC_SETACL, vp);
4566 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
4567 NFSZERO_ATTRBIT(&attrbits);
4568 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
4569 (void) nfsv4_fillattr(nd, vnode_mount(vp), vp, aclp, NULL, NULL, 0,
4570 &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0);
4571 error = nfscl_request(nd, vp, p, cred, stuff);
4574 /* Don't care about the pre/postop attributes */
4575 mbuf_freem(nd->nd_mrep);
4576 return (nd->nd_repstat);
4580 * Do the NFSv4.1 Exchange ID.
4583 nfsrpc_exchangeid(struct nfsmount *nmp, struct nfsclclient *clp,
4584 struct nfssockreq *nrp, uint32_t exchflags, struct nfsclds **dspp,
4585 struct ucred *cred, NFSPROC_T *p)
4587 uint32_t *tl, v41flags;
4588 struct nfsrv_descript nfsd;
4589 struct nfsrv_descript *nd = &nfsd;
4590 struct nfsclds *dsp;
4591 struct timespec verstime;
4595 nfscl_reqstart(nd, NFSPROC_EXCHANGEID, nmp, NULL, 0, NULL, NULL);
4596 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4597 *tl++ = txdr_unsigned(nfsboottime.tv_sec); /* Client owner */
4598 *tl = txdr_unsigned(clp->nfsc_rev);
4599 (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen);
4601 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
4602 *tl++ = txdr_unsigned(exchflags);
4603 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE);
4605 /* Set the implementation id4 */
4606 *tl = txdr_unsigned(1);
4607 (void) nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
4608 (void) nfsm_strtom(nd, version, strlen(version));
4609 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
4610 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */
4611 verstime.tv_nsec = 0;
4612 txdr_nfsv4time(&verstime, tl);
4613 nd->nd_flag |= ND_USEGSSNAME;
4614 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
4615 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4616 NFSCL_DEBUG(1, "exchangeid err=%d reps=%d\n", error,
4617 (int)nd->nd_repstat);
4620 if (nd->nd_repstat == 0) {
4621 NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_UNSIGNED + NFSX_HYPER);
4622 len = fxdr_unsigned(int, *(tl + 7));
4623 if (len < 0 || len > NFSV4_OPAQUELIMIT) {
4624 error = NFSERR_BADXDR;
4627 dsp = malloc(sizeof(struct nfsclds) + len + 1, M_NFSCLDS,
4629 dsp->nfsclds_expire = NFSD_MONOSEC + clp->nfsc_renew;
4630 dsp->nfsclds_servownlen = len;
4631 dsp->nfsclds_sess.nfsess_clientid.lval[0] = *tl++;
4632 dsp->nfsclds_sess.nfsess_clientid.lval[1] = *tl++;
4633 dsp->nfsclds_sess.nfsess_sequenceid =
4634 fxdr_unsigned(uint32_t, *tl++);
4635 v41flags = fxdr_unsigned(uint32_t, *tl);
4636 if ((v41flags & NFSV4EXCH_USEPNFSMDS) != 0 &&
4637 NFSHASPNFSOPT(nmp)) {
4638 NFSCL_DEBUG(1, "set PNFS\n");
4640 nmp->nm_state |= NFSSTA_PNFS;
4642 dsp->nfsclds_flags |= NFSCLDS_MDS;
4644 if ((v41flags & NFSV4EXCH_USEPNFSDS) != 0)
4645 dsp->nfsclds_flags |= NFSCLDS_DS;
4647 nd->nd_repstat = nfsrv_mtostr(nd,
4648 dsp->nfsclds_serverown, len);
4649 if (nd->nd_repstat == 0) {
4650 mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF);
4651 mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession",
4653 nfscl_initsessionslots(&dsp->nfsclds_sess);
4656 free(dsp, M_NFSCLDS);
4658 error = nd->nd_repstat;
4660 mbuf_freem(nd->nd_mrep);
4665 * Do the NFSv4.1 Create Session.
4668 nfsrpc_createsession(struct nfsmount *nmp, struct nfsclsession *sep,
4669 struct nfssockreq *nrp, uint32_t sequenceid, int mds, struct ucred *cred,
4672 uint32_t crflags, maxval, *tl;
4673 struct nfsrv_descript nfsd;
4674 struct nfsrv_descript *nd = &nfsd;
4677 nfscl_reqstart(nd, NFSPROC_CREATESESSION, nmp, NULL, 0, NULL, NULL);
4678 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4679 *tl++ = sep->nfsess_clientid.lval[0];
4680 *tl++ = sep->nfsess_clientid.lval[1];
4681 *tl++ = txdr_unsigned(sequenceid);
4682 crflags = (NFSMNT_RDONLY(nmp->nm_mountp) ? 0 : NFSV4CRSESS_PERSIST);
4683 if (nfscl_enablecallb != 0 && nfs_numnfscbd > 0 && mds != 0)
4684 crflags |= NFSV4CRSESS_CONNBACKCHAN;
4685 *tl = txdr_unsigned(crflags);
4687 /* Fill in fore channel attributes. */
4688 NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4689 *tl++ = 0; /* Header pad size */
4690 *tl++ = txdr_unsigned(nmp->nm_wsize + NFS_MAXXDR);/* Max request size */
4691 *tl++ = txdr_unsigned(nmp->nm_rsize + NFS_MAXXDR);/* Max reply size */
4692 *tl++ = txdr_unsigned(4096); /* Max response size cached */
4693 *tl++ = txdr_unsigned(20); /* Max operations */
4694 *tl++ = txdr_unsigned(64); /* Max slots */
4695 *tl = 0; /* No rdma ird */
4697 /* Fill in back channel attributes. */
4698 NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4699 *tl++ = 0; /* Header pad size */
4700 *tl++ = txdr_unsigned(10000); /* Max request size */
4701 *tl++ = txdr_unsigned(10000); /* Max response size */
4702 *tl++ = txdr_unsigned(4096); /* Max response size cached */
4703 *tl++ = txdr_unsigned(4); /* Max operations */
4704 *tl++ = txdr_unsigned(NFSV4_CBSLOTS); /* Max slots */
4705 *tl = 0; /* No rdma ird */
4707 NFSM_BUILD(tl, uint32_t *, 8 * NFSX_UNSIGNED);
4708 *tl++ = txdr_unsigned(NFS_CALLBCKPROG); /* Call back prog # */
4710 /* Allow AUTH_SYS callbacks as uid, gid == 0. */
4711 *tl++ = txdr_unsigned(1); /* Auth_sys only */
4712 *tl++ = txdr_unsigned(AUTH_SYS); /* AUTH_SYS type */
4713 *tl++ = txdr_unsigned(nfsboottime.tv_sec); /* time stamp */
4714 *tl++ = 0; /* Null machine name */
4715 *tl++ = 0; /* Uid == 0 */
4716 *tl++ = 0; /* Gid == 0 */
4717 *tl = 0; /* No additional gids */
4718 nd->nd_flag |= ND_USEGSSNAME;
4719 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, NFS_PROG,
4720 NFS_VER4, NULL, 1, NULL, NULL);
4723 if (nd->nd_repstat == 0) {
4724 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID +
4726 bcopy(tl, sep->nfsess_sessionid, NFSX_V4SESSIONID);
4727 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4728 sep->nfsess_sequenceid = fxdr_unsigned(uint32_t, *tl++);
4729 crflags = fxdr_unsigned(uint32_t, *tl);
4730 if ((crflags & NFSV4CRSESS_PERSIST) != 0 && mds != 0) {
4732 nmp->nm_state |= NFSSTA_SESSPERSIST;
4736 /* Get the fore channel slot count. */
4737 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4738 tl++; /* Skip the header pad size. */
4740 /* Make sure nm_wsize is small enough. */
4741 maxval = fxdr_unsigned(uint32_t, *tl++);
4742 while (maxval < nmp->nm_wsize + NFS_MAXXDR) {
4743 if (nmp->nm_wsize > 8096)
4749 /* Make sure nm_rsize is small enough. */
4750 maxval = fxdr_unsigned(uint32_t, *tl++);
4751 while (maxval < nmp->nm_rsize + NFS_MAXXDR) {
4752 if (nmp->nm_rsize > 8096)
4758 sep->nfsess_maxcache = fxdr_unsigned(int, *tl++);
4760 sep->nfsess_foreslots = fxdr_unsigned(uint16_t, *tl++);
4761 NFSCL_DEBUG(4, "fore slots=%d\n", (int)sep->nfsess_foreslots);
4762 irdcnt = fxdr_unsigned(int, *tl);
4764 NFSM_DISSECT(tl, uint32_t *, irdcnt * NFSX_UNSIGNED);
4766 /* and the back channel slot count. */
4767 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4769 sep->nfsess_backslots = fxdr_unsigned(uint16_t, *tl);
4770 NFSCL_DEBUG(4, "back slots=%d\n", (int)sep->nfsess_backslots);
4772 error = nd->nd_repstat;
4774 mbuf_freem(nd->nd_mrep);
4779 * Do the NFSv4.1 Destroy Session.
4782 nfsrpc_destroysession(struct nfsmount *nmp, struct nfsclclient *clp,
4783 struct ucred *cred, NFSPROC_T *p)
4786 struct nfsrv_descript nfsd;
4787 struct nfsrv_descript *nd = &nfsd;
4789 struct nfsclsession *tsep;
4791 nfscl_reqstart(nd, NFSPROC_DESTROYSESSION, nmp, NULL, 0, NULL, NULL);
4792 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4793 tsep = nfsmnt_mdssession(nmp);
4794 bcopy(tsep->nfsess_sessionid, tl, NFSX_V4SESSIONID);
4795 nd->nd_flag |= ND_USEGSSNAME;
4796 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4797 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4800 error = nd->nd_repstat;
4801 mbuf_freem(nd->nd_mrep);
4806 * Do the NFSv4.1 Destroy Client.
4809 nfsrpc_destroyclient(struct nfsmount *nmp, struct nfsclclient *clp,
4810 struct ucred *cred, NFSPROC_T *p)
4813 struct nfsrv_descript nfsd;
4814 struct nfsrv_descript *nd = &nfsd;
4816 struct nfsclsession *tsep;
4818 nfscl_reqstart(nd, NFSPROC_DESTROYCLIENT, nmp, NULL, 0, NULL, NULL);
4819 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4820 tsep = nfsmnt_mdssession(nmp);
4821 *tl++ = tsep->nfsess_clientid.lval[0];
4822 *tl = tsep->nfsess_clientid.lval[1];
4823 nd->nd_flag |= ND_USEGSSNAME;
4824 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4825 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4828 error = nd->nd_repstat;
4829 mbuf_freem(nd->nd_mrep);
4834 * Do the NFSv4.1 LayoutGet.
4837 nfsrpc_layoutget(struct nfsmount *nmp, uint8_t *fhp, int fhlen, int iomode,
4838 uint64_t offset, uint64_t len, uint64_t minlen, int layoutlen,
4839 nfsv4stateid_t *stateidp, int *retonclosep, struct nfsclflayouthead *flhp,
4840 struct ucred *cred, NFSPROC_T *p, void *stuff)
4842 struct nfsrv_descript nfsd, *nd = &nfsd;
4845 nfscl_reqstart(nd, NFSPROC_LAYOUTGET, nmp, fhp, fhlen, NULL, NULL);
4846 nfsrv_setuplayoutget(nd, iomode, offset, len, minlen, stateidp,
4848 nd->nd_flag |= ND_USEGSSNAME;
4849 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4850 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4851 NFSCL_DEBUG(4, "layget err=%d st=%d\n", error, nd->nd_repstat);
4854 if (nd->nd_repstat == 0)
4855 error = nfsrv_parselayoutget(nd, stateidp, retonclosep, flhp);
4856 if (error == 0 && nd->nd_repstat != 0)
4857 error = nd->nd_repstat;
4858 mbuf_freem(nd->nd_mrep);
4863 * Do the NFSv4.1 Get Device Info.
4866 nfsrpc_getdeviceinfo(struct nfsmount *nmp, uint8_t *deviceid, int layouttype,
4867 uint32_t *notifybitsp, struct nfscldevinfo **ndip, struct ucred *cred,
4871 struct nfsrv_descript nfsd;
4872 struct nfsrv_descript *nd = &nfsd;
4873 struct sockaddr_storage ss;
4874 struct nfsclds *dsp = NULL, **dspp;
4875 struct nfscldevinfo *ndi;
4876 int addrcnt, bitcnt, error, i, isudp, j, pos, safilled, stripecnt;
4877 uint8_t stripeindex;
4881 nfscl_reqstart(nd, NFSPROC_GETDEVICEINFO, nmp, NULL, 0, NULL, NULL);
4882 NFSM_BUILD(tl, uint32_t *, NFSX_V4DEVICEID + 3 * NFSX_UNSIGNED);
4883 NFSBCOPY(deviceid, tl, NFSX_V4DEVICEID);
4884 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
4885 *tl++ = txdr_unsigned(layouttype);
4886 *tl++ = txdr_unsigned(100000);
4887 if (notifybitsp != NULL && *notifybitsp != 0) {
4888 *tl = txdr_unsigned(1); /* One word of bits. */
4889 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4890 *tl = txdr_unsigned(*notifybitsp);
4892 *tl = txdr_unsigned(0);
4893 nd->nd_flag |= ND_USEGSSNAME;
4894 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4895 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4898 if (nd->nd_repstat == 0) {
4899 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED);
4900 if (layouttype != fxdr_unsigned(int, *tl++))
4901 printf("EEK! devinfo layout type not same!\n");
4902 stripecnt = fxdr_unsigned(int, *++tl);
4903 NFSCL_DEBUG(4, "stripecnt=%d\n", stripecnt);
4904 if (stripecnt < 1 || stripecnt > 4096) {
4905 printf("NFS devinfo stripecnt %d: out of range\n",
4907 error = NFSERR_BADXDR;
4910 NFSM_DISSECT(tl, uint32_t *, (stripecnt + 1) * NFSX_UNSIGNED);
4911 addrcnt = fxdr_unsigned(int, *(tl + stripecnt));
4912 NFSCL_DEBUG(4, "addrcnt=%d\n", addrcnt);
4913 if (addrcnt < 1 || addrcnt > 128) {
4914 printf("NFS devinfo addrcnt %d: out of range\n",
4916 error = NFSERR_BADXDR;
4921 * Now we know how many stripe indices and addresses, so
4922 * we can allocate the structure the correct size.
4924 i = (stripecnt * sizeof(uint8_t)) / sizeof(struct nfsclds *)
4926 NFSCL_DEBUG(4, "stripeindices=%d\n", i);
4927 ndi = malloc(sizeof(*ndi) + (addrcnt + i) *
4928 sizeof(struct nfsclds *), M_NFSDEVINFO, M_WAITOK | M_ZERO);
4929 NFSBCOPY(deviceid, ndi->nfsdi_deviceid, NFSX_V4DEVICEID);
4930 ndi->nfsdi_refcnt = 0;
4931 ndi->nfsdi_stripecnt = stripecnt;
4932 ndi->nfsdi_addrcnt = addrcnt;
4933 /* Fill in the stripe indices. */
4934 for (i = 0; i < stripecnt; i++) {
4935 stripeindex = fxdr_unsigned(uint8_t, *tl++);
4936 NFSCL_DEBUG(4, "stripeind=%d\n", stripeindex);
4937 if (stripeindex >= addrcnt) {
4938 printf("NFS devinfo stripeindex %d: too big\n",
4940 error = NFSERR_BADXDR;
4943 nfsfldi_setstripeindex(ndi, i, stripeindex);
4946 /* Now, dissect the server address(es). */
4948 for (i = 0; i < addrcnt; i++) {
4949 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4950 cnt = fxdr_unsigned(uint32_t, *tl);
4952 printf("NFS devinfo 0 len addrlist\n");
4953 error = NFSERR_BADXDR;
4956 dspp = nfsfldi_addr(ndi, i);
4957 pos = arc4random() % cnt; /* Choose one. */
4959 for (j = 0; j < cnt; j++) {
4960 error = nfsv4_getipaddr(nd, &ss, &isudp);
4961 if (error != 0 && error != EPERM) {
4962 error = NFSERR_BADXDR;
4965 if (error == 0 && isudp == 0) {
4968 * - use "pos" entry if it is of the
4969 * same af_family or none of them
4970 * is of the same af_family
4972 * - use the first one of the same
4975 if ((safilled == 0 && ss.ss_family ==
4976 nmp->nm_nam->sa_family) ||
4978 (safilled == 0 || ss.ss_family ==
4979 nmp->nm_nam->sa_family)) ||
4980 (safilled == 1 && ss.ss_family ==
4981 nmp->nm_nam->sa_family)) {
4982 error = nfsrpc_fillsa(nmp, &ss,
4987 nmp->nm_nam->sa_family)
4999 /* And the notify bits. */
5000 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5001 if (safilled != 0) {
5002 bitcnt = fxdr_unsigned(int, *tl);
5004 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5005 if (notifybitsp != NULL)
5007 fxdr_unsigned(uint32_t, *tl);
5013 if (nd->nd_repstat != 0)
5014 error = nd->nd_repstat;
5016 if (error != 0 && ndi != NULL)
5017 nfscl_freedevinfo(ndi);
5018 mbuf_freem(nd->nd_mrep);
5023 * Do the NFSv4.1 LayoutCommit.
5026 nfsrpc_layoutcommit(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim,
5027 uint64_t off, uint64_t len, uint64_t lastbyte, nfsv4stateid_t *stateidp,
5028 int layouttype, int layoutupdatecnt, uint8_t *layp, struct ucred *cred,
5029 NFSPROC_T *p, void *stuff)
5032 struct nfsrv_descript nfsd, *nd = &nfsd;
5033 int error, outcnt, i;
5036 nfscl_reqstart(nd, NFSPROC_LAYOUTCOMMIT, nmp, fh, fhlen, NULL, NULL);
5037 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
5039 txdr_hyper(off, tl);
5041 txdr_hyper(len, tl);
5044 *tl++ = newnfs_true;
5046 *tl++ = newnfs_false;
5047 *tl++ = txdr_unsigned(stateidp->seqid);
5048 *tl++ = stateidp->other[0];
5049 *tl++ = stateidp->other[1];
5050 *tl++ = stateidp->other[2];
5051 *tl++ = newnfs_true;
5054 else if (lastbyte >= (off + len))
5055 lastbyte = off + len - 1;
5056 txdr_hyper(lastbyte, tl);
5058 *tl++ = newnfs_false;
5059 *tl++ = txdr_unsigned(layouttype);
5060 *tl = txdr_unsigned(layoutupdatecnt);
5061 if (layoutupdatecnt > 0) {
5062 KASSERT(layouttype != NFSLAYOUT_NFSV4_1_FILES,
5063 ("Must be nil for Files Layout"));
5064 outcnt = NFSM_RNDUP(layoutupdatecnt);
5065 NFSM_BUILD(cp, uint8_t *, outcnt);
5066 NFSBCOPY(layp, cp, layoutupdatecnt);
5067 cp += layoutupdatecnt;
5068 for (i = 0; i < (outcnt - layoutupdatecnt); i++)
5071 nd->nd_flag |= ND_USEGSSNAME;
5072 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5073 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5076 error = nd->nd_repstat;
5077 mbuf_freem(nd->nd_mrep);
5082 * Do the NFSv4.1 LayoutReturn.
5085 nfsrpc_layoutreturn(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim,
5086 int layouttype, uint32_t iomode, int layoutreturn, uint64_t offset,
5087 uint64_t len, nfsv4stateid_t *stateidp, int layoutcnt, uint32_t *layp,
5088 struct ucred *cred, NFSPROC_T *p, void *stuff)
5091 struct nfsrv_descript nfsd, *nd = &nfsd;
5092 int error, outcnt, i;
5095 nfscl_reqstart(nd, NFSPROC_LAYOUTRETURN, nmp, fh, fhlen, NULL, NULL);
5096 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED);
5098 *tl++ = newnfs_true;
5100 *tl++ = newnfs_false;
5101 *tl++ = txdr_unsigned(layouttype);
5102 *tl++ = txdr_unsigned(iomode);
5103 *tl = txdr_unsigned(layoutreturn);
5104 if (layoutreturn == NFSLAYOUTRETURN_FILE) {
5105 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
5107 txdr_hyper(offset, tl);
5109 txdr_hyper(len, tl);
5111 NFSCL_DEBUG(4, "layoutret stseq=%d\n", (int)stateidp->seqid);
5112 *tl++ = txdr_unsigned(stateidp->seqid);
5113 *tl++ = stateidp->other[0];
5114 *tl++ = stateidp->other[1];
5115 *tl++ = stateidp->other[2];
5116 *tl = txdr_unsigned(layoutcnt);
5117 if (layoutcnt > 0) {
5118 outcnt = NFSM_RNDUP(layoutcnt);
5119 NFSM_BUILD(cp, uint8_t *, outcnt);
5120 NFSBCOPY(layp, cp, layoutcnt);
5122 for (i = 0; i < (outcnt - layoutcnt); i++)
5126 nd->nd_flag |= ND_USEGSSNAME;
5127 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5128 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5131 if (nd->nd_repstat == 0) {
5132 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5134 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
5135 stateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
5136 stateidp->other[0] = *tl++;
5137 stateidp->other[1] = *tl++;
5138 stateidp->other[2] = *tl;
5141 error = nd->nd_repstat;
5143 mbuf_freem(nd->nd_mrep);
5148 * Acquire a layout and devinfo, if possible. The caller must have acquired
5149 * a reference count on the nfsclclient structure before calling this.
5150 * Return the layout in lypp with a reference count on it, if successful.
5153 nfsrpc_getlayout(struct nfsmount *nmp, vnode_t vp, struct nfsfh *nfhp,
5154 int iomode, uint32_t *notifybitsp, nfsv4stateid_t *stateidp, uint64_t off,
5155 struct nfscllayout **lypp, struct ucred *cred, NFSPROC_T *p)
5157 struct nfscllayout *lyp;
5158 struct nfsclflayout *flp;
5159 struct nfsclflayouthead flh;
5160 int error = 0, islocked, layoutlen, recalled, retonclose;
5161 nfsv4stateid_t stateid;
5162 struct nfsclsession *tsep;
5166 * If lyp is returned non-NULL, there will be a refcnt (shared lock)
5167 * on it, iff flp != NULL or a lock (exclusive lock) on it iff
5170 lyp = nfscl_getlayout(nmp->nm_clp, nfhp->nfh_fh, nfhp->nfh_len,
5171 off, &flp, &recalled);
5173 if (lyp == NULL || flp == NULL) {
5177 tsep = nfsmnt_mdssession(nmp);
5178 layoutlen = tsep->nfsess_maxcache -
5179 (NFSX_STATEID + 3 * NFSX_UNSIGNED);
5182 stateid.other[0] = stateidp->other[0];
5183 stateid.other[1] = stateidp->other[1];
5184 stateid.other[2] = stateidp->other[2];
5185 error = nfsrpc_layoutget(nmp, nfhp->nfh_fh,
5186 nfhp->nfh_len, iomode, (uint64_t)0, UINT64_MAX,
5187 (uint64_t)0, layoutlen, &stateid, &retonclose,
5188 &flh, cred, p, NULL);
5191 stateid.seqid = lyp->nfsly_stateid.seqid;
5192 stateid.other[0] = lyp->nfsly_stateid.other[0];
5193 stateid.other[1] = lyp->nfsly_stateid.other[1];
5194 stateid.other[2] = lyp->nfsly_stateid.other[2];
5195 error = nfsrpc_layoutget(nmp, nfhp->nfh_fh,
5196 nfhp->nfh_len, iomode, off, UINT64_MAX,
5197 (uint64_t)0, layoutlen, &stateid, &retonclose,
5198 &flh, cred, p, NULL);
5200 error = nfsrpc_layoutgetres(nmp, vp, nfhp->nfh_fh,
5201 nfhp->nfh_len, &stateid, retonclose, notifybitsp, &lyp,
5202 &flh, error, NULL, cred, p);
5205 else if (islocked != 0)
5206 nfscl_rellayout(lyp, 1);
5213 * Do a TCP connection plus exchange id and create session.
5214 * If successful, a "struct nfsclds" is linked into the list for the
5215 * mount point and a pointer to it is returned.
5218 nfsrpc_fillsa(struct nfsmount *nmp, struct sockaddr_storage *ssp,
5219 struct nfsclds **dspp, NFSPROC_T *p)
5221 struct sockaddr_in *msad, *sad, *ssd;
5222 struct sockaddr_in6 *msad6, *sad6, *ssd6;
5223 struct nfsclclient *clp;
5224 struct nfssockreq *nrp;
5225 struct nfsclds *dsp, *tdsp;
5227 enum nfsclds_state retv;
5228 uint32_t sequenceid;
5230 KASSERT(nmp->nm_sockreq.nr_cred != NULL,
5231 ("nfsrpc_fillsa: NULL nr_cred"));
5237 if (ssp->ss_family == AF_INET) {
5238 ssd = (struct sockaddr_in *)ssp;
5242 * Check to see if we already have a session for this
5243 * address that is usable for a DS.
5244 * Note that the MDS's address is in a different place
5245 * than the sessions already acquired for DS's.
5247 msad = (struct sockaddr_in *)nmp->nm_sockreq.nr_nam;
5248 tdsp = TAILQ_FIRST(&nmp->nm_sess);
5249 while (tdsp != NULL) {
5250 if (msad != NULL && msad->sin_family == AF_INET &&
5251 ssd->sin_addr.s_addr == msad->sin_addr.s_addr &&
5252 ssd->sin_port == msad->sin_port &&
5253 (tdsp->nfsclds_flags & NFSCLDS_DS) != 0 &&
5254 tdsp->nfsclds_sess.nfsess_defunct == 0) {
5257 NFSCL_DEBUG(4, "fnd same addr\n");
5260 tdsp = TAILQ_NEXT(tdsp, nfsclds_list);
5261 if (tdsp != NULL && tdsp->nfsclds_sockp != NULL)
5262 msad = (struct sockaddr_in *)
5263 tdsp->nfsclds_sockp->nr_nam;
5269 /* No IP address match, so look for new/trunked one. */
5270 sad = malloc(sizeof(*sad), M_SONAME, M_WAITOK | M_ZERO);
5271 sad->sin_len = sizeof(*sad);
5272 sad->sin_family = AF_INET;
5273 sad->sin_port = ssd->sin_port;
5274 sad->sin_addr.s_addr = ssd->sin_addr.s_addr;
5275 nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO);
5276 nrp->nr_nam = (struct sockaddr *)sad;
5277 } else if (ssp->ss_family == AF_INET6) {
5278 ssd6 = (struct sockaddr_in6 *)ssp;
5282 * Check to see if we already have a session for this
5283 * address that is usable for a DS.
5284 * Note that the MDS's address is in a different place
5285 * than the sessions already acquired for DS's.
5287 msad6 = (struct sockaddr_in6 *)nmp->nm_sockreq.nr_nam;
5288 tdsp = TAILQ_FIRST(&nmp->nm_sess);
5289 while (tdsp != NULL) {
5290 if (msad6 != NULL && msad6->sin6_family == AF_INET6 &&
5291 IN6_ARE_ADDR_EQUAL(&ssd6->sin6_addr,
5292 &msad6->sin6_addr) &&
5293 ssd6->sin6_port == msad6->sin6_port &&
5294 (tdsp->nfsclds_flags & NFSCLDS_DS) != 0 &&
5295 tdsp->nfsclds_sess.nfsess_defunct == 0) {
5300 tdsp = TAILQ_NEXT(tdsp, nfsclds_list);
5301 if (tdsp != NULL && tdsp->nfsclds_sockp != NULL)
5302 msad6 = (struct sockaddr_in6 *)
5303 tdsp->nfsclds_sockp->nr_nam;
5309 /* No IP address match, so look for new/trunked one. */
5310 sad6 = malloc(sizeof(*sad6), M_SONAME, M_WAITOK | M_ZERO);
5311 sad6->sin6_len = sizeof(*sad6);
5312 sad6->sin6_family = AF_INET6;
5313 sad6->sin6_port = ssd6->sin6_port;
5314 NFSBCOPY(&ssd6->sin6_addr, &sad6->sin6_addr,
5315 sizeof(struct in6_addr));
5316 nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO);
5317 nrp->nr_nam = (struct sockaddr *)sad6;
5321 nrp->nr_sotype = SOCK_STREAM;
5322 mtx_init(&nrp->nr_mtx, "nfssock", NULL, MTX_DEF);
5323 nrp->nr_prog = NFS_PROG;
5324 nrp->nr_vers = NFS_VER4;
5327 * Use the credentials that were used for the mount, which are
5328 * in nmp->nm_sockreq.nr_cred for newnfs_connect() etc.
5329 * Ref. counting the credentials with crhold() is probably not
5330 * necessary, since nm_sockreq.nr_cred won't be crfree()'d until
5331 * unmount, but I did it anyhow.
5333 nrp->nr_cred = crhold(nmp->nm_sockreq.nr_cred);
5334 error = newnfs_connect(nmp, nrp, NULL, p, 0);
5335 NFSCL_DEBUG(3, "DS connect=%d\n", error);
5337 /* Now, do the exchangeid and create session. */
5339 error = nfsrpc_exchangeid(nmp, clp, nrp, NFSV4EXCH_USEPNFSDS,
5340 &dsp, nrp->nr_cred, p);
5341 NFSCL_DEBUG(3, "DS exchangeid=%d\n", error);
5343 newnfs_disconnect(nrp);
5346 dsp->nfsclds_sockp = nrp;
5348 retv = nfscl_getsameserver(nmp, dsp, &tdsp);
5349 NFSCL_DEBUG(3, "getsame ret=%d\n", retv);
5350 if (retv == NFSDSP_USETHISSESSION) {
5353 * If there is already a session for this server,
5356 (void)newnfs_disconnect(nrp);
5357 nfscl_freenfsclds(dsp);
5361 if (retv == NFSDSP_SEQTHISSESSION)
5362 sequenceid = tdsp->nfsclds_sess.nfsess_sequenceid;
5364 sequenceid = dsp->nfsclds_sess.nfsess_sequenceid;
5366 error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess,
5367 nrp, sequenceid, 0, nrp->nr_cred, p);
5368 NFSCL_DEBUG(3, "DS createsess=%d\n", error);
5370 NFSFREECRED(nrp->nr_cred);
5371 NFSFREEMUTEX(&nrp->nr_mtx);
5372 free(nrp->nr_nam, M_SONAME);
5373 free(nrp, M_NFSSOCKREQ);
5376 NFSCL_DEBUG(3, "add DS session\n");
5378 * Put it at the end of the list. That way the list
5379 * is ordered by when the entry was added. This matters
5380 * since the one done first is the one that should be
5381 * used for sequencid'ing any subsequent create sessions.
5384 TAILQ_INSERT_TAIL(&nmp->nm_sess, dsp, nfsclds_list);
5387 } else if (dsp != NULL) {
5388 newnfs_disconnect(nrp);
5389 nfscl_freenfsclds(dsp);
5395 * Do the NFSv4.1 Reclaim Complete.
5398 nfsrpc_reclaimcomplete(struct nfsmount *nmp, struct ucred *cred, NFSPROC_T *p)
5401 struct nfsrv_descript nfsd;
5402 struct nfsrv_descript *nd = &nfsd;
5405 nfscl_reqstart(nd, NFSPROC_RECLAIMCOMPL, nmp, NULL, 0, NULL, NULL);
5406 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5408 nd->nd_flag |= ND_USEGSSNAME;
5409 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5410 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5413 error = nd->nd_repstat;
5414 mbuf_freem(nd->nd_mrep);
5419 * Initialize the slot tables for a session.
5422 nfscl_initsessionslots(struct nfsclsession *sep)
5426 for (i = 0; i < NFSV4_CBSLOTS; i++) {
5427 if (sep->nfsess_cbslots[i].nfssl_reply != NULL)
5428 m_freem(sep->nfsess_cbslots[i].nfssl_reply);
5429 NFSBZERO(&sep->nfsess_cbslots[i], sizeof(struct nfsslot));
5431 for (i = 0; i < 64; i++)
5432 sep->nfsess_slotseq[i] = 0;
5433 sep->nfsess_slots = 0;
5437 * Called to try and do an I/O operation via an NFSv4.1 Data Server (DS).
5440 nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
5441 uint32_t rwaccess, int docommit, struct ucred *cred, NFSPROC_T *p)
5443 struct nfsnode *np = VTONFS(vp);
5444 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
5445 struct nfscllayout *layp;
5446 struct nfscldevinfo *dip;
5447 struct nfsclflayout *rflp;
5448 nfsv4stateid_t stateid;
5449 struct ucred *newcred;
5450 uint64_t lastbyte, len, off, oresid, xfer;
5451 int eof, error, iolaymode, recalled;
5454 if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || nfs_numnfscbd == 0 ||
5455 (np->n_flag & NNOLAYOUT) != 0)
5457 /* Now, get a reference cnt on the clientid for this mount. */
5458 if (nfscl_getref(nmp) == 0)
5461 /* Find an appropriate stateid. */
5462 newcred = NFSNEWCRED(cred);
5463 error = nfscl_getstateid(vp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len,
5464 rwaccess, 1, newcred, p, &stateid, &lckp);
5466 NFSFREECRED(newcred);
5470 /* Search for a layout for this file. */
5471 off = uiop->uio_offset;
5472 layp = nfscl_getlayout(nmp->nm_clp, np->n_fhp->nfh_fh,
5473 np->n_fhp->nfh_len, off, &rflp, &recalled);
5474 if (layp == NULL || rflp == NULL) {
5475 if (recalled != 0) {
5476 NFSFREECRED(newcred);
5481 nfscl_rellayout(layp, (rflp == NULL) ? 1 : 0);
5484 /* Try and get a Layout, if it is supported. */
5485 if (rwaccess == NFSV4OPEN_ACCESSWRITE ||
5486 (np->n_flag & NWRITEOPENED) != 0)
5487 iolaymode = NFSLAYOUTIOMODE_RW;
5489 iolaymode = NFSLAYOUTIOMODE_READ;
5490 error = nfsrpc_getlayout(nmp, vp, np->n_fhp, iolaymode,
5491 NULL, &stateid, off, &layp, newcred, p);
5494 np->n_flag |= NNOLAYOUT;
5497 nfscl_lockderef(lckp);
5498 NFSFREECRED(newcred);
5500 nfscl_rellayout(layp, 0);
5507 * Loop around finding a layout that works for the first part of
5508 * this I/O operation, and then call the function that actually
5512 len = (uint64_t)uiop->uio_resid;
5513 while (len > 0 && error == 0 && eof == 0) {
5514 off = uiop->uio_offset;
5515 error = nfscl_findlayoutforio(layp, off, rwaccess, &rflp);
5517 oresid = xfer = (uint64_t)uiop->uio_resid;
5518 if (xfer > (rflp->nfsfl_end - rflp->nfsfl_off))
5519 xfer = rflp->nfsfl_end - rflp->nfsfl_off;
5520 dip = nfscl_getdevinfo(nmp->nm_clp, rflp->nfsfl_dev,
5523 error = nfscl_doflayoutio(vp, uiop, iomode,
5524 must_commit, &eof, &stateid, rwaccess, dip,
5525 layp, rflp, off, xfer, docommit, newcred,
5527 nfscl_reldevinfo(dip);
5528 lastbyte = off + xfer - 1;
5531 if (lastbyte > layp->nfsly_lastbyte)
5532 layp->nfsly_lastbyte = lastbyte;
5534 } else if (error == NFSERR_OPENMODE &&
5535 rwaccess == NFSV4OPEN_ACCESSREAD) {
5537 nmp->nm_state |= NFSSTA_OPENMODE;
5543 len -= (oresid - (uint64_t)uiop->uio_resid);
5547 nfscl_lockderef(lckp);
5548 NFSFREECRED(newcred);
5549 nfscl_rellayout(layp, 0);
5555 * Find a file layout that will handle the first bytes of the requested
5556 * range and return the information from it needed to to the I/O operation.
5559 nfscl_findlayoutforio(struct nfscllayout *lyp, uint64_t off, uint32_t rwaccess,
5560 struct nfsclflayout **retflpp)
5562 struct nfsclflayout *flp, *nflp, *rflp;
5567 /* For reading, do the Read list first and then the Write list. */
5569 if (rw == NFSV4OPEN_ACCESSREAD)
5570 flp = LIST_FIRST(&lyp->nfsly_flayread);
5572 flp = LIST_FIRST(&lyp->nfsly_flayrw);
5573 while (flp != NULL) {
5574 nflp = LIST_NEXT(flp, nfsfl_list);
5575 if (flp->nfsfl_off > off)
5577 if (flp->nfsfl_end > off &&
5578 (rflp == NULL || rflp->nfsfl_end < flp->nfsfl_end))
5582 if (rw == NFSV4OPEN_ACCESSREAD)
5583 rw = NFSV4OPEN_ACCESSWRITE;
5588 /* This one covers the most bytes starting at off. */
5596 * Do I/O using an NFSv4.1 file layout.
5599 nfscl_doflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
5600 int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp,
5601 struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off,
5602 uint64_t len, int docommit, struct ucred *cred, NFSPROC_T *p)
5604 uint64_t io_off, rel_off, stripe_unit_size, transfer, xfer;
5605 int commit_thru_mds, error, stripe_index, stripe_pos;
5608 struct nfsclds **dspp;
5611 rel_off = off - flp->nfsfl_patoff;
5612 stripe_unit_size = (flp->nfsfl_util >> 6) & 0x3ffffff;
5613 stripe_pos = (rel_off / stripe_unit_size + flp->nfsfl_stripe1) %
5614 dp->nfsdi_stripecnt;
5615 transfer = stripe_unit_size - (rel_off % stripe_unit_size);
5618 /* Loop around, doing I/O for each stripe unit. */
5619 while (len > 0 && error == 0) {
5620 stripe_index = nfsfldi_stripeindex(dp, stripe_pos);
5621 dspp = nfsfldi_addr(dp, stripe_index);
5622 if (len > transfer && docommit == 0)
5626 if ((flp->nfsfl_util & NFSFLAYUTIL_DENSE) != 0) {
5628 if (stripe_pos >= flp->nfsfl_fhcnt)
5630 fhp = flp->nfsfl_fh[stripe_pos];
5631 io_off = (rel_off / (stripe_unit_size *
5632 dp->nfsdi_stripecnt)) * stripe_unit_size +
5633 rel_off % stripe_unit_size;
5635 /* Sparse layout. */
5636 if (flp->nfsfl_fhcnt > 1) {
5637 if (stripe_index >= flp->nfsfl_fhcnt)
5639 fhp = flp->nfsfl_fh[stripe_index];
5640 } else if (flp->nfsfl_fhcnt == 1)
5641 fhp = flp->nfsfl_fh[0];
5646 if ((flp->nfsfl_util & NFSFLAYUTIL_COMMIT_THRU_MDS) != 0) {
5647 commit_thru_mds = 1;
5651 commit_thru_mds = 0;
5652 mtx_lock(&np->n_mtx);
5653 np->n_flag |= NDSCOMMIT;
5654 mtx_unlock(&np->n_mtx);
5656 if (docommit != 0) {
5658 error = nfsrpc_commitds(vp, io_off, xfer,
5659 *dspp, fhp, cred, p);
5662 * Set both eof and uio_resid = 0 to end any
5666 uiop->uio_resid = 0;
5668 mtx_lock(&np->n_mtx);
5669 np->n_flag &= ~NDSCOMMIT;
5670 mtx_unlock(&np->n_mtx);
5672 } else if (rwflag == FREAD)
5673 error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp,
5674 io_off, xfer, fhp, cred, p);
5676 error = nfsrpc_writeds(vp, uiop, iomode, must_commit,
5677 stateidp, *dspp, io_off, xfer, fhp, commit_thru_mds,
5681 lyp->nfsly_flags |= NFSLY_WRITTEN;
5686 transfer = stripe_unit_size;
5687 stripe_pos = (stripe_pos + 1) % dp->nfsdi_stripecnt;
5696 * The actual read RPC done to a DS.
5699 nfsrpc_readds(vnode_t vp, struct uio *uiop, nfsv4stateid_t *stateidp, int *eofp,
5700 struct nfsclds *dsp, uint64_t io_off, int len, struct nfsfh *fhp,
5701 struct ucred *cred, NFSPROC_T *p)
5705 struct nfsrv_descript nfsd;
5706 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
5707 struct nfsrv_descript *nd = &nfsd;
5708 struct nfssockreq *nrp;
5711 nfscl_reqstart(nd, NFSPROC_READDS, nmp, fhp->nfh_fh, fhp->nfh_len,
5712 NULL, &dsp->nfsclds_sess);
5713 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO);
5714 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED * 3);
5715 txdr_hyper(io_off, tl);
5716 *(tl + 2) = txdr_unsigned(len);
5717 nrp = dsp->nfsclds_sockp;
5719 /* If NULL, use the MDS socket. */
5720 nrp = &nmp->nm_sockreq;
5721 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
5722 NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
5725 if (nd->nd_repstat != 0) {
5726 error = nd->nd_repstat;
5729 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5730 *eofp = fxdr_unsigned(int, *tl);
5731 NFSM_STRSIZ(retlen, len);
5732 error = nfsm_mbufuio(nd, uiop, retlen);
5734 if (nd->nd_mrep != NULL)
5735 mbuf_freem(nd->nd_mrep);
5740 * The actual write RPC done to a DS.
5743 nfsrpc_writeds(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
5744 nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len,
5745 struct nfsfh *fhp, int commit_thru_mds, struct ucred *cred, NFSPROC_T *p)
5748 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
5749 int error, rlen, commit, committed = NFSWRITE_FILESYNC;
5751 struct nfsrv_descript nfsd;
5752 struct nfsrv_descript *nd = &nfsd;
5753 struct nfssockreq *nrp;
5755 KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1"));
5757 nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh, fhp->nfh_len,
5758 NULL, &dsp->nfsclds_sess);
5759 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO);
5760 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
5761 txdr_hyper(io_off, tl);
5763 *tl++ = txdr_unsigned(*iomode);
5764 *tl = txdr_unsigned(len);
5765 nfsm_uiombuf(nd, uiop, len);
5766 nrp = dsp->nfsclds_sockp;
5768 /* If NULL, use the MDS socket. */
5769 nrp = &nmp->nm_sockreq;
5770 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
5771 NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
5774 if (nd->nd_repstat != 0) {
5776 * In case the rpc gets retried, roll
5777 * the uio fileds changed by nfsm_uiombuf()
5780 uiop->uio_offset -= len;
5781 uio_uio_resid_add(uiop, len);
5782 uio_iov_base_add(uiop, -len);
5783 uio_iov_len_add(uiop, len);
5784 error = nd->nd_repstat;
5786 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF);
5787 rlen = fxdr_unsigned(int, *tl++);
5791 } else if (rlen < len) {
5792 backup = len - rlen;
5793 uio_iov_base_add(uiop, -(backup));
5794 uio_iov_len_add(uiop, backup);
5795 uiop->uio_offset -= backup;
5796 uio_uio_resid_add(uiop, backup);
5799 commit = fxdr_unsigned(int, *tl++);
5802 * Return the lowest commitment level
5803 * obtained by any of the RPCs.
5805 if (committed == NFSWRITE_FILESYNC)
5807 else if (committed == NFSWRITE_DATASYNC &&
5808 commit == NFSWRITE_UNSTABLE)
5810 if (commit_thru_mds != 0) {
5812 if (!NFSHASWRITEVERF(nmp)) {
5813 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
5814 NFSSETWRITEVERF(nmp);
5815 } else if (NFSBCMP(tl, nmp->nm_verf, NFSX_VERF)) {
5817 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
5822 if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) {
5823 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
5824 dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF;
5825 } else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) {
5827 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
5833 if (nd->nd_mrep != NULL)
5834 mbuf_freem(nd->nd_mrep);
5835 *iomode = committed;
5836 if (nd->nd_repstat != 0 && error == 0)
5837 error = nd->nd_repstat;
5842 * Free up the nfsclds structure.
5845 nfscl_freenfsclds(struct nfsclds *dsp)
5851 if (dsp->nfsclds_sockp != NULL) {
5852 NFSFREECRED(dsp->nfsclds_sockp->nr_cred);
5853 NFSFREEMUTEX(&dsp->nfsclds_sockp->nr_mtx);
5854 free(dsp->nfsclds_sockp->nr_nam, M_SONAME);
5855 free(dsp->nfsclds_sockp, M_NFSSOCKREQ);
5857 NFSFREEMUTEX(&dsp->nfsclds_mtx);
5858 NFSFREEMUTEX(&dsp->nfsclds_sess.nfsess_mtx);
5859 for (i = 0; i < NFSV4_CBSLOTS; i++) {
5860 if (dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply != NULL)
5862 dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply);
5864 free(dsp, M_NFSCLDS);
5867 static enum nfsclds_state
5868 nfscl_getsameserver(struct nfsmount *nmp, struct nfsclds *newdsp,
5869 struct nfsclds **retdspp)
5871 struct nfsclds *dsp, *cur_dsp;
5874 * Search the list of nfsclds structures for one with the same
5878 TAILQ_FOREACH(dsp, &nmp->nm_sess, nfsclds_list) {
5879 if (dsp->nfsclds_servownlen == newdsp->nfsclds_servownlen &&
5880 dsp->nfsclds_servownlen != 0 &&
5881 !NFSBCMP(dsp->nfsclds_serverown, newdsp->nfsclds_serverown,
5882 dsp->nfsclds_servownlen) &&
5883 dsp->nfsclds_sess.nfsess_defunct == 0) {
5884 NFSCL_DEBUG(4, "fnd same fdsp=%p dsp=%p flg=0x%x\n",
5885 TAILQ_FIRST(&nmp->nm_sess), dsp,
5886 dsp->nfsclds_flags);
5887 /* Server major id matches. */
5888 if ((dsp->nfsclds_flags & NFSCLDS_DS) != 0) {
5890 return (NFSDSP_USETHISSESSION);
5894 * Note the first match, so it can be used for
5895 * sequence'ing new sessions.
5897 if (cur_dsp == NULL)
5901 if (cur_dsp != NULL) {
5903 return (NFSDSP_SEQTHISSESSION);
5905 return (NFSDSP_NOTFOUND);
5909 * NFS commit rpc to a NFSv4.1 DS.
5912 nfsrpc_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp,
5913 struct nfsfh *fhp, struct ucred *cred, NFSPROC_T *p)
5916 struct nfsrv_descript nfsd, *nd = &nfsd;
5917 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
5918 struct nfssockreq *nrp;
5922 nfscl_reqstart(nd, NFSPROC_COMMITDS, nmp, fhp->nfh_fh, fhp->nfh_len,
5923 NULL, &dsp->nfsclds_sess);
5924 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
5925 txdr_hyper(offset, tl);
5927 *tl = txdr_unsigned(cnt);
5928 nrp = dsp->nfsclds_sockp;
5930 /* If NULL, use the MDS socket. */
5931 nrp = &nmp->nm_sockreq;
5932 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
5933 NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
5936 if (nd->nd_repstat == 0) {
5937 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
5939 if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) {
5940 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
5941 error = NFSERR_STALEWRITEVERF;
5946 if (error == 0 && nd->nd_repstat != 0)
5947 error = nd->nd_repstat;
5948 mbuf_freem(nd->nd_mrep);
5953 * Set up the XDR arguments for the LayoutGet operation.
5956 nfsrv_setuplayoutget(struct nfsrv_descript *nd, int iomode, uint64_t offset,
5957 uint64_t len, uint64_t minlen, nfsv4stateid_t *stateidp, int layoutlen,
5962 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
5964 *tl++ = newnfs_false; /* Don't signal availability. */
5965 *tl++ = txdr_unsigned(NFSLAYOUT_NFSV4_1_FILES);
5966 *tl++ = txdr_unsigned(iomode);
5967 txdr_hyper(offset, tl);
5969 txdr_hyper(len, tl);
5971 txdr_hyper(minlen, tl);
5973 if (usecurstateid != 0) {
5974 /* Special stateid for Current stateid. */
5975 *tl++ = txdr_unsigned(1);
5980 *tl++ = txdr_unsigned(stateidp->seqid);
5981 NFSCL_DEBUG(4, "layget seq=%d\n", (int)stateidp->seqid);
5982 *tl++ = stateidp->other[0];
5983 *tl++ = stateidp->other[1];
5984 *tl++ = stateidp->other[2];
5986 *tl = txdr_unsigned(layoutlen);
5990 * Parse the reply for a successful LayoutGet operation.
5993 nfsrv_parselayoutget(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp,
5994 int *retonclosep, struct nfsclflayouthead *flhp)
5997 struct nfsclflayout *flp, *prevflp, *tflp;
5998 int cnt, error, gotiomode, fhcnt, nfhlen, i, j;
6006 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_STATEID);
6011 stateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
6012 NFSCL_DEBUG(4, "retoncls=%d stseq=%d\n", *retonclosep,
6013 (int)stateidp->seqid);
6014 stateidp->other[0] = *tl++;
6015 stateidp->other[1] = *tl++;
6016 stateidp->other[2] = *tl++;
6017 cnt = fxdr_unsigned(int, *tl);
6018 NFSCL_DEBUG(4, "layg cnt=%d\n", cnt);
6019 if (cnt <= 0 || cnt > 10000) {
6020 /* Don't accept more than 10000 layouts in reply. */
6021 error = NFSERR_BADXDR;
6024 for (i = 0; i < cnt; i++) {
6025 /* Dissect all the way to the file handle cnt. */
6026 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_HYPER +
6027 6 * NFSX_UNSIGNED + NFSX_V4DEVICEID);
6028 fhcnt = fxdr_unsigned(int, *(tl + 11 +
6029 NFSX_V4DEVICEID / NFSX_UNSIGNED));
6030 NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt);
6031 if (fhcnt < 0 || fhcnt > 100) {
6032 /* Don't accept more than 100 file handles. */
6033 error = NFSERR_BADXDR;
6037 flp = malloc(sizeof(*flp) + (fhcnt - 1) *
6038 sizeof(struct nfsfh *), M_NFSFLAYOUT, M_WAITOK);
6040 flp = malloc(sizeof(*flp), M_NFSFLAYOUT, M_WAITOK);
6041 flp->nfsfl_flags = 0;
6042 flp->nfsfl_fhcnt = 0;
6043 flp->nfsfl_devp = NULL;
6044 flp->nfsfl_off = fxdr_hyper(tl); tl += 2;
6045 retlen = fxdr_hyper(tl); tl += 2;
6046 if (flp->nfsfl_off + retlen < flp->nfsfl_off)
6047 flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off;
6049 flp->nfsfl_end = flp->nfsfl_off + retlen;
6050 flp->nfsfl_iomode = fxdr_unsigned(int, *tl++);
6051 if (gotiomode == -1)
6052 gotiomode = flp->nfsfl_iomode;
6053 if (fxdr_unsigned(int, *tl++) != NFSLAYOUT_NFSV4_1_FILES) {
6054 printf("NFSv4.1: got non-files layout\n");
6055 error = NFSERR_BADXDR;
6058 NFSBCOPY(++tl, flp->nfsfl_dev, NFSX_V4DEVICEID);
6059 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
6060 flp->nfsfl_util = fxdr_unsigned(uint32_t, *tl++);
6061 NFSCL_DEBUG(4, "flutil=0x%x\n", flp->nfsfl_util);
6062 flp->nfsfl_stripe1 = fxdr_unsigned(uint32_t, *tl++);
6063 flp->nfsfl_patoff = fxdr_hyper(tl); tl += 2;
6064 if (fxdr_unsigned(int, *tl) != fhcnt) {
6065 printf("EEK! bad fhcnt\n");
6066 error = NFSERR_BADXDR;
6069 for (j = 0; j < fhcnt; j++) {
6070 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
6071 nfhlen = fxdr_unsigned(int, *tl);
6072 if (nfhlen <= 0 || nfhlen > NFSX_V4FHMAX) {
6073 error = NFSERR_BADXDR;
6076 nfhp = malloc(sizeof(*nfhp) + nfhlen - 1, M_NFSFH,
6078 flp->nfsfl_fh[j] = nfhp;
6080 nfhp->nfh_len = nfhlen;
6081 NFSM_DISSECT(cp, uint8_t *, NFSM_RNDUP(nfhlen));
6082 NFSBCOPY(cp, nfhp->nfh_fh, nfhlen);
6084 if (flp->nfsfl_iomode == gotiomode) {
6085 /* Keep the list in increasing offset order. */
6086 tflp = LIST_FIRST(flhp);
6088 while (tflp != NULL &&
6089 tflp->nfsfl_off < flp->nfsfl_off) {
6091 tflp = LIST_NEXT(tflp, nfsfl_list);
6093 if (prevflp == NULL)
6094 LIST_INSERT_HEAD(flhp, flp, nfsfl_list);
6096 LIST_INSERT_AFTER(prevflp, flp,
6099 printf("nfscl_layoutget(): got wrong iomode\n");
6100 nfscl_freeflayout(flp);
6105 if (error != 0 && flp != NULL)
6106 nfscl_freeflayout(flp);
6111 * Similar to nfsrpc_getlayout(), except that it uses nfsrpc_openlayget(),
6112 * so that it does both an Open and a Layoutget.
6115 nfsrpc_getopenlayout(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp,
6116 int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode,
6117 struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp,
6118 struct ucred *cred, NFSPROC_T *p)
6120 struct nfscllayout *lyp;
6121 struct nfsclflayout *flp;
6122 struct nfsclflayouthead flh;
6123 int error, islocked, layoutlen, recalled, retonclose, usecurstateid;
6125 nfsv4stateid_t stateid;
6126 struct nfsclsession *tsep;
6130 * If lyp is returned non-NULL, there will be a refcnt (shared lock)
6131 * on it, iff flp != NULL or a lock (exclusive lock) on it iff
6134 lyp = nfscl_getlayout(nmp->nm_clp, newfhp, newfhlen, 0, &flp,
6136 NFSCL_DEBUG(4, "nfsrpc_getopenlayout nfscl_getlayout lyp=%p\n", lyp);
6139 else if (flp != NULL)
6143 if ((lyp == NULL || flp == NULL) && recalled == 0) {
6145 tsep = nfsmnt_mdssession(nmp);
6146 layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID +
6152 stateid.seqid = lyp->nfsly_stateid.seqid;
6153 stateid.other[0] = lyp->nfsly_stateid.other[0];
6154 stateid.other[1] = lyp->nfsly_stateid.other[1];
6155 stateid.other[2] = lyp->nfsly_stateid.other[2];
6157 error = nfsrpc_openlayoutrpc(nmp, vp, nfhp, fhlen,
6158 newfhp, newfhlen, mode, op, name, namelen,
6159 dpp, &stateid, usecurstateid, layoutlen,
6160 &retonclose, &flh, &laystat, cred, p);
6161 NFSCL_DEBUG(4, "aft nfsrpc_openlayoutrpc laystat=%d err=%d\n",
6163 laystat = nfsrpc_layoutgetres(nmp, vp, newfhp, newfhlen,
6164 &stateid, retonclose, NULL, &lyp, &flh, laystat, &islocked,
6167 error = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp, newfhlen,
6168 mode, op, name, namelen, dpp, 0, 0, cred, p, 0, 0);
6170 nfscl_rellayout(lyp, 1);
6171 else if (islocked == 1)
6172 nfscl_rellayout(lyp, 0);
6177 * This function does an Open+LayoutGet for an NFSv4.1 mount with pNFS
6178 * enabled, only for the CLAIM_NULL case. All other NFSv4 Opens are
6179 * handled by nfsrpc_openrpc().
6180 * For the case where op == NULL, dvp is the directory. When op != NULL, it
6184 nfsrpc_openlayoutrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp,
6185 int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode,
6186 struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp,
6187 nfsv4stateid_t *stateidp, int usecurstateid,
6188 int layoutlen, int *retonclosep, struct nfsclflayouthead *flhp,
6189 int *laystatp, struct ucred *cred, NFSPROC_T *p)
6192 struct nfsrv_descript nfsd, *nd = &nfsd;
6193 struct nfscldeleg *ndp = NULL;
6194 struct nfsvattr nfsva;
6195 struct nfsclsession *tsep;
6196 uint32_t rflags, deleg;
6197 nfsattrbit_t attrbits;
6198 int error, ret, acesize, limitby, iomode;
6202 nfscl_reqstart(nd, NFSPROC_OPENLAYGET, nmp, nfhp, fhlen, NULL, NULL);
6203 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
6204 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
6205 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
6206 *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
6207 tsep = nfsmnt_mdssession(nmp);
6208 *tl++ = tsep->nfsess_clientid.lval[0];
6209 *tl = tsep->nfsess_clientid.lval[1];
6210 nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN);
6211 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
6212 *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE);
6213 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
6214 nfsm_strtom(nd, name, namelen);
6215 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
6216 *tl = txdr_unsigned(NFSV4OP_GETATTR);
6217 NFSZERO_ATTRBIT(&attrbits);
6218 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
6219 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY);
6220 nfsrv_putattrbit(nd, &attrbits);
6221 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
6222 *tl = txdr_unsigned(NFSV4OP_LAYOUTGET);
6223 if ((mode & NFSV4OPEN_ACCESSWRITE) != 0)
6224 iomode = NFSLAYOUTIOMODE_RW;
6226 iomode = NFSLAYOUTIOMODE_READ;
6227 nfsrv_setuplayoutget(nd, iomode, 0, UINT64_MAX, 0, stateidp,
6228 layoutlen, usecurstateid);
6229 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
6230 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
6233 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
6234 if (nd->nd_repstat != 0)
6235 *laystatp = nd->nd_repstat;
6236 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
6237 /* ND_NOMOREDATA will be set if the Open operation failed. */
6238 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
6240 op->nfso_stateid.seqid = *tl++;
6241 op->nfso_stateid.other[0] = *tl++;
6242 op->nfso_stateid.other[1] = *tl++;
6243 op->nfso_stateid.other[2] = *tl;
6244 rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
6245 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
6248 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
6249 deleg = fxdr_unsigned(u_int32_t, *tl);
6250 if (deleg == NFSV4OPEN_DELEGATEREAD ||
6251 deleg == NFSV4OPEN_DELEGATEWRITE) {
6252 if (!(op->nfso_own->nfsow_clp->nfsc_flags &
6253 NFSCLFLAGS_FIRSTDELEG))
6254 op->nfso_own->nfsow_clp->nfsc_flags |=
6255 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
6256 ndp = malloc(sizeof(struct nfscldeleg) + newfhlen,
6257 M_NFSCLDELEG, M_WAITOK);
6258 LIST_INIT(&ndp->nfsdl_owner);
6259 LIST_INIT(&ndp->nfsdl_lock);
6260 ndp->nfsdl_clp = op->nfso_own->nfsow_clp;
6261 ndp->nfsdl_fhlen = newfhlen;
6262 NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen);
6263 newnfs_copyincred(cred, &ndp->nfsdl_cred);
6264 nfscl_lockinit(&ndp->nfsdl_rwlock);
6265 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
6267 ndp->nfsdl_stateid.seqid = *tl++;
6268 ndp->nfsdl_stateid.other[0] = *tl++;
6269 ndp->nfsdl_stateid.other[1] = *tl++;
6270 ndp->nfsdl_stateid.other[2] = *tl++;
6271 ret = fxdr_unsigned(int, *tl);
6272 if (deleg == NFSV4OPEN_DELEGATEWRITE) {
6273 ndp->nfsdl_flags = NFSCLDL_WRITE;
6275 * Indicates how much the file can grow.
6277 NFSM_DISSECT(tl, u_int32_t *,
6279 limitby = fxdr_unsigned(int, *tl++);
6281 case NFSV4OPEN_LIMITSIZE:
6282 ndp->nfsdl_sizelimit = fxdr_hyper(tl);
6284 case NFSV4OPEN_LIMITBLOCKS:
6285 ndp->nfsdl_sizelimit =
6286 fxdr_unsigned(u_int64_t, *tl++);
6287 ndp->nfsdl_sizelimit *=
6288 fxdr_unsigned(u_int64_t, *tl);
6291 error = NFSERR_BADXDR;
6295 ndp->nfsdl_flags = NFSCLDL_READ;
6297 ndp->nfsdl_flags |= NFSCLDL_RECALL;
6298 error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, &ret,
6302 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
6303 error = NFSERR_BADXDR;
6306 if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) != 0 ||
6307 nfscl_assumeposixlocks)
6308 op->nfso_posixlock = 1;
6310 op->nfso_posixlock = 0;
6311 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
6312 /* If the 2nd element == NFS_OK, the Getattr succeeded. */
6314 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
6315 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
6316 NULL, NULL, NULL, p, cred);
6320 ndp->nfsdl_change = nfsva.na_filerev;
6321 ndp->nfsdl_modtime = nfsva.na_mtime;
6322 ndp->nfsdl_flags |= NFSCLDL_MODTIMESET;
6327 * At this point, the Open has succeeded, so set
6328 * nd_repstat = NFS_OK. If the Layoutget failed,
6329 * this function just won't return a layout.
6331 if (nd->nd_repstat == 0) {
6332 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
6333 *laystatp = fxdr_unsigned(int, *++tl);
6334 if (*laystatp == 0) {
6335 error = nfsrv_parselayoutget(nd,
6336 stateidp, retonclosep, flhp);
6341 nd->nd_repstat = 0; /* Return 0 for Open. */
6344 if (nd->nd_repstat != 0 && error == 0)
6345 error = nd->nd_repstat;
6347 free(ndp, M_NFSCLDELEG);
6348 mbuf_freem(nd->nd_mrep);
6353 * Similar nfsrpc_createv4(), but also does the LayoutGet operation.
6354 * Used only for mounts with pNFS enabled.
6357 nfsrpc_createlayout(vnode_t dvp, char *name, int namelen, struct vattr *vap,
6358 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp,
6359 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
6360 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
6361 int *dattrflagp, void *dstuff, int *unlockedp, nfsv4stateid_t *stateidp,
6362 int usecurstateid, int layoutlen, int *retonclosep,
6363 struct nfsclflayouthead *flhp, int *laystatp)
6366 int error = 0, deleg, newone, ret, acesize, limitby;
6367 struct nfsrv_descript nfsd, *nd = &nfsd;
6368 struct nfsclopen *op;
6369 struct nfscldeleg *dp = NULL;
6372 struct nfsclsession *tsep;
6373 nfsattrbit_t attrbits;
6374 nfsv4stateid_t stateid;
6376 struct nfsmount *nmp;
6378 nmp = VFSTONFS(dvp->v_mount);
6386 if (namelen > NFS_MAXNAMLEN)
6387 return (ENAMETOOLONG);
6388 NFSCL_REQSTART(nd, NFSPROC_CREATELAYGET, dvp);
6390 * For V4, this is actually an Open op.
6392 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
6393 *tl++ = txdr_unsigned(owp->nfsow_seqid);
6394 *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
6395 NFSV4OPEN_ACCESSREAD);
6396 *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE);
6397 tsep = nfsmnt_mdssession(nmp);
6398 *tl++ = tsep->nfsess_clientid.lval[0];
6399 *tl = tsep->nfsess_clientid.lval[1];
6400 nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN);
6401 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
6402 *tl++ = txdr_unsigned(NFSV4OPEN_CREATE);
6403 if ((fmode & O_EXCL) != 0) {
6404 if (NFSHASSESSPERSIST(nmp)) {
6405 /* Use GUARDED for persistent sessions. */
6406 *tl = txdr_unsigned(NFSCREATE_GUARDED);
6407 nfscl_fillsattr(nd, vap, dvp, 0, 0);
6409 /* Otherwise, use EXCLUSIVE4_1. */
6410 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41);
6411 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
6412 *tl++ = cverf.lval[0];
6413 *tl = cverf.lval[1];
6414 nfscl_fillsattr(nd, vap, dvp, 0, 0);
6417 *tl = txdr_unsigned(NFSCREATE_UNCHECKED);
6418 nfscl_fillsattr(nd, vap, dvp, 0, 0);
6420 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
6421 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
6422 nfsm_strtom(nd, name, namelen);
6423 /* Get the new file's handle and attributes, plus save the FH. */
6424 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
6425 *tl++ = txdr_unsigned(NFSV4OP_SAVEFH);
6426 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
6427 *tl = txdr_unsigned(NFSV4OP_GETATTR);
6428 NFSGETATTR_ATTRBIT(&attrbits);
6429 nfsrv_putattrbit(nd, &attrbits);
6430 /* Get the directory's post-op attributes. */
6431 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
6432 *tl = txdr_unsigned(NFSV4OP_PUTFH);
6433 nfsm_fhtom(nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0);
6434 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
6435 *tl = txdr_unsigned(NFSV4OP_GETATTR);
6436 nfsrv_putattrbit(nd, &attrbits);
6437 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
6438 *tl++ = txdr_unsigned(NFSV4OP_RESTOREFH);
6439 *tl = txdr_unsigned(NFSV4OP_LAYOUTGET);
6440 nfsrv_setuplayoutget(nd, NFSLAYOUTIOMODE_RW, 0, UINT64_MAX, 0, stateidp,
6441 layoutlen, usecurstateid);
6442 error = nfscl_request(nd, dvp, p, cred, dstuff);
6445 NFSCL_DEBUG(4, "nfsrpc_createlayout stat=%d err=%d\n", nd->nd_repstat,
6447 if (nd->nd_repstat != 0)
6448 *laystatp = nd->nd_repstat;
6449 NFSCL_INCRSEQID(owp->nfsow_seqid, nd);
6450 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
6451 NFSCL_DEBUG(4, "nfsrpc_createlayout open succeeded\n");
6452 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
6454 stateid.seqid = *tl++;
6455 stateid.other[0] = *tl++;
6456 stateid.other[1] = *tl++;
6457 stateid.other[2] = *tl;
6458 rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
6459 nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
6460 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
6461 deleg = fxdr_unsigned(int, *tl);
6462 if (deleg == NFSV4OPEN_DELEGATEREAD ||
6463 deleg == NFSV4OPEN_DELEGATEWRITE) {
6464 if (!(owp->nfsow_clp->nfsc_flags &
6465 NFSCLFLAGS_FIRSTDELEG))
6466 owp->nfsow_clp->nfsc_flags |=
6467 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
6468 dp = malloc(sizeof(struct nfscldeleg) + NFSX_V4FHMAX,
6469 M_NFSCLDELEG, M_WAITOK);
6470 LIST_INIT(&dp->nfsdl_owner);
6471 LIST_INIT(&dp->nfsdl_lock);
6472 dp->nfsdl_clp = owp->nfsow_clp;
6473 newnfs_copyincred(cred, &dp->nfsdl_cred);
6474 nfscl_lockinit(&dp->nfsdl_rwlock);
6475 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
6477 dp->nfsdl_stateid.seqid = *tl++;
6478 dp->nfsdl_stateid.other[0] = *tl++;
6479 dp->nfsdl_stateid.other[1] = *tl++;
6480 dp->nfsdl_stateid.other[2] = *tl++;
6481 ret = fxdr_unsigned(int, *tl);
6482 if (deleg == NFSV4OPEN_DELEGATEWRITE) {
6483 dp->nfsdl_flags = NFSCLDL_WRITE;
6485 * Indicates how much the file can grow.
6487 NFSM_DISSECT(tl, u_int32_t *,
6489 limitby = fxdr_unsigned(int, *tl++);
6491 case NFSV4OPEN_LIMITSIZE:
6492 dp->nfsdl_sizelimit = fxdr_hyper(tl);
6494 case NFSV4OPEN_LIMITBLOCKS:
6495 dp->nfsdl_sizelimit =
6496 fxdr_unsigned(u_int64_t, *tl++);
6497 dp->nfsdl_sizelimit *=
6498 fxdr_unsigned(u_int64_t, *tl);
6501 error = NFSERR_BADXDR;
6505 dp->nfsdl_flags = NFSCLDL_READ;
6508 dp->nfsdl_flags |= NFSCLDL_RECALL;
6509 error = nfsrv_dissectace(nd, &dp->nfsdl_ace, &ret,
6513 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
6514 error = NFSERR_BADXDR;
6518 /* Now, we should have the status for the SaveFH. */
6519 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
6521 NFSCL_DEBUG(4, "nfsrpc_createlayout SaveFH ok\n");
6523 * Now, process the GetFH and Getattr for the newly
6524 * created file. nfscl_mtofh() will set
6525 * ND_NOMOREDATA if these weren't successful.
6527 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
6528 NFSCL_DEBUG(4, "aft nfscl_mtofh err=%d\n", error);
6532 nd->nd_flag |= ND_NOMOREDATA;
6533 /* Now we have the PutFH and Getattr for the directory. */
6534 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
6535 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
6537 nd->nd_flag |= ND_NOMOREDATA;
6539 NFSM_DISSECT(tl, uint32_t *, 2 *
6542 nd->nd_flag |= ND_NOMOREDATA;
6545 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
6546 /* Load the directory attributes. */
6547 error = nfsm_loadattr(nd, dnap);
6548 NFSCL_DEBUG(4, "aft nfsm_loadattr err=%d\n", error);
6552 if (dp != NULL && *attrflagp != 0) {
6553 dp->nfsdl_change = nnap->na_filerev;
6554 dp->nfsdl_modtime = nnap->na_mtime;
6555 dp->nfsdl_flags |= NFSCLDL_MODTIMESET;
6558 * We can now complete the Open state.
6562 dp->nfsdl_fhlen = nfhp->nfh_len;
6563 NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh,
6567 * Get an Open structure that will be
6568 * attached to the OpenOwner, acquired already.
6570 error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len,
6571 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0,
6572 cred, p, NULL, &op, &newone, NULL, 0);
6575 op->nfso_stateid = stateid;
6576 newnfs_copyincred(cred, &op->nfso_cred);
6578 nfscl_openrelease(nmp, op, error, newone);
6581 /* Now, handle the RestoreFH and LayoutGet. */
6582 if (nd->nd_repstat == 0) {
6583 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
6584 *laystatp = fxdr_unsigned(int, *(tl + 3));
6585 if (*laystatp == 0) {
6586 error = nfsrv_parselayoutget(nd,
6587 stateidp, retonclosep, flhp);
6591 NFSCL_DEBUG(4, "aft nfsrv_parselayout err=%d\n",
6597 if (nd->nd_repstat != 0 && error == 0)
6598 error = nd->nd_repstat;
6599 if (error == NFSERR_STALECLIENTID || error == NFSERR_BADSESSION)
6600 nfscl_initiate_recovery(owp->nfsow_clp);
6602 NFSCL_DEBUG(4, "eo nfsrpc_createlayout err=%d\n", error);
6606 free(dp, M_NFSCLDELEG);
6607 mbuf_freem(nd->nd_mrep);
6612 * Similar to nfsrpc_getopenlayout(), except that it used for the Create case.
6615 nfsrpc_getcreatelayout(vnode_t dvp, char *name, int namelen, struct vattr *vap,
6616 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp,
6617 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
6618 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
6619 int *dattrflagp, void *dstuff, int *unlockedp)
6621 struct nfscllayout *lyp;
6622 struct nfsclflayouthead flh;
6624 struct nfsclsession *tsep;
6625 struct nfsmount *nmp;
6626 nfsv4stateid_t stateid;
6627 int error, layoutlen, retonclose, laystat;
6630 nmp = VFSTONFS(dvp->v_mount);
6632 tsep = nfsmnt_mdssession(nmp);
6633 layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID + 3 * NFSX_UNSIGNED);
6634 error = nfsrpc_createlayout(dvp, name, namelen, vap, cverf, fmode,
6635 owp, dpp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp,
6636 dstuff, unlockedp, &stateid, 1, layoutlen, &retonclose, &flh,
6638 NFSCL_DEBUG(4, "aft nfsrpc_createlayoutrpc laystat=%d err=%d\n",
6642 laystat = nfsrpc_layoutgetres(nmp, dvp, nfhp->nfh_fh, nfhp->nfh_len,
6643 &stateid, retonclose, NULL, &lyp, &flh, laystat, NULL, cred, p);
6645 nfscl_rellayout(lyp, 0);
6650 * Process the results of a layoutget() operation.
6653 nfsrpc_layoutgetres(struct nfsmount *nmp, vnode_t vp, uint8_t *newfhp,
6654 int newfhlen, nfsv4stateid_t *stateidp, int retonclose, uint32_t *notifybit,
6655 struct nfscllayout **lypp, struct nfsclflayouthead *flhp,
6656 int laystat, int *islockedp, struct ucred *cred, NFSPROC_T *p)
6658 struct nfsclflayout *tflp;
6659 struct nfscldevinfo *dip;
6661 if (laystat == NFSERR_UNKNLAYOUTTYPE) {
6663 NFSCL_DEBUG(1, "disable PNFS\n");
6665 nmp->nm_state &= ~NFSSTA_PNFS;
6669 NFSCL_DEBUG(4, "nfsrpc_layoutgetres at FOREACH\n");
6670 LIST_FOREACH(tflp, flhp, nfsfl_list) {
6671 laystat = nfscl_adddevinfo(nmp, NULL, tflp);
6672 NFSCL_DEBUG(4, "aft adddev=%d\n", laystat);
6674 laystat = nfsrpc_getdeviceinfo(nmp,
6675 tflp->nfsfl_dev, NFSLAYOUT_NFSV4_1_FILES,
6676 notifybit, &dip, cred, p);
6677 NFSCL_DEBUG(4, "aft nfsrpc_gdi=%d\n",
6681 laystat = nfscl_adddevinfo(nmp, dip, tflp);
6683 printf("getlayout: cannot add\n");
6689 * nfscl_layout() always returns with the nfsly_lock
6690 * set to a refcnt (shared lock).
6691 * Passing in dvp is sufficient, since it is only used to
6692 * get the fsid for the file system.
6694 laystat = nfscl_layout(nmp, vp, newfhp, newfhlen, stateidp,
6695 retonclose, flhp, lypp, cred, p);
6696 NFSCL_DEBUG(4, "nfsrpc_layoutgetres: aft nfscl_layout=%d\n",
6698 if (laystat == 0 && islockedp != NULL)