2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
38 * Rpc op calls, generally called from the vnode op calls or through the
39 * buffer cache, for NFS v2, 3 and 4.
40 * These do not normally make any changes to vnode arguments or use
41 * structures that might change between the VFS variants. The returned
42 * arguments are all at the end, after the NFSPROC_T *p one.
46 #include "opt_inet6.h"
48 #include <fs/nfs/nfsport.h>
49 #include <sys/sysctl.h>
51 SYSCTL_DECL(_vfs_nfs);
53 static int nfsignore_eexist = 0;
54 SYSCTL_INT(_vfs_nfs, OID_AUTO, ignore_eexist, CTLFLAG_RW,
55 &nfsignore_eexist, 0, "NFS ignore EEXIST replies for mkdir/symlink");
60 extern int nfs_numnfscbd;
61 extern struct timeval nfsboottime;
62 extern u_int32_t newnfs_false, newnfs_true;
63 extern nfstype nfsv34_type[9];
64 extern int nfsrv_useacl;
65 extern char nfsv4_callbackaddr[INET6_ADDRSTRLEN];
66 extern int nfscl_debuglevel;
68 int nfstest_outofseq = 0;
69 int nfscl_assumeposixlocks = 1;
70 int nfscl_enablecallb = 0;
71 short nfsv4_cbport = NFSV4_CBPORT;
72 int nfstest_openallsetattr = 0;
73 #endif /* !APPLEKEXT */
75 #define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1))
78 * nfscl_getsameserver() can return one of three values:
79 * NFSDSP_USETHISSESSION - Use this session for the DS.
80 * NFSDSP_SEQTHISSESSION - Use the nfsclds_sequence field of this dsp for new
82 * NFSDSP_NOTFOUND - No matching server was found.
85 NFSDSP_USETHISSESSION = 0,
86 NFSDSP_SEQTHISSESSION = 1,
90 static int nfsrpc_setattrrpc(vnode_t , struct vattr *, nfsv4stateid_t *,
91 struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, void *);
92 static int nfsrpc_readrpc(vnode_t , struct uio *, struct ucred *,
93 nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *, void *);
94 static int nfsrpc_writerpc(vnode_t , struct uio *, int *, int *,
95 struct ucred *, nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *,
97 static int nfsrpc_createv23(vnode_t , char *, int, struct vattr *,
98 nfsquad_t, int, struct ucred *, NFSPROC_T *, struct nfsvattr *,
99 struct nfsvattr *, struct nfsfh **, int *, int *, void *);
100 static int nfsrpc_createv4(vnode_t , char *, int, struct vattr *,
101 nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, struct ucred *,
102 NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, struct nfsfh **, int *,
103 int *, void *, int *);
104 static int nfsrpc_locku(struct nfsrv_descript *, struct nfsmount *,
105 struct nfscllockowner *, u_int64_t, u_int64_t,
106 u_int32_t, struct ucred *, NFSPROC_T *, int);
107 static int nfsrpc_setaclrpc(vnode_t, struct ucred *, NFSPROC_T *,
108 struct acl *, nfsv4stateid_t *, void *);
109 static int nfsrpc_getlayout(struct nfsmount *, vnode_t, struct nfsfh *, int,
110 uint32_t *, nfsv4stateid_t *, uint64_t, struct nfscllayout **,
111 struct ucred *, NFSPROC_T *);
112 static int nfsrpc_fillsa(struct nfsmount *, struct sockaddr_storage *,
113 struct nfsclds **, NFSPROC_T *);
114 static void nfscl_initsessionslots(struct nfsclsession *);
115 static int nfscl_doflayoutio(vnode_t, struct uio *, int *, int *, int *,
116 nfsv4stateid_t *, int, struct nfscldevinfo *, struct nfscllayout *,
117 struct nfsclflayout *, uint64_t, uint64_t, 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 long dotfileid, dotdotfileid = 0;
2790 u_int32_t fakefileno = 0xffffffff, rderr;
2792 nfsattrbit_t attrbits, dattrbits;
2793 u_int32_t *tl2 = NULL;
2796 KASSERT(uiop->uio_iovcnt == 1 &&
2797 (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0,
2798 ("nfs readdirrpc bad uio"));
2801 * There is no point in reading a lot more than uio_resid, however
2802 * adding one additional DIRBLKSIZ makes sense. Since uio_resid
2803 * and nm_readdirsize are both exact multiples of DIRBLKSIZ, this
2804 * will never make readsize > nm_readdirsize.
2806 readsize = nmp->nm_readdirsize;
2807 if (readsize > uio_uio_resid(uiop))
2808 readsize = uio_uio_resid(uiop) + DIRBLKSIZ;
2813 tresid = uio_uio_resid(uiop);
2814 cookie.lval[0] = cookiep->nfsuquad[0];
2815 cookie.lval[1] = cookiep->nfsuquad[1];
2819 * For NFSv4, first create the "." and ".." entries.
2821 if (NFSHASNFSV4(nmp)) {
2822 reqsize = 6 * NFSX_UNSIGNED;
2823 NFSGETATTR_ATTRBIT(&dattrbits);
2824 NFSZERO_ATTRBIT(&attrbits);
2825 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID);
2826 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TYPE);
2827 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
2828 NFSATTRBIT_MOUNTEDONFILEID)) {
2829 NFSSETBIT_ATTRBIT(&attrbits,
2830 NFSATTRBIT_MOUNTEDONFILEID);
2834 * Must fake it. Use the fileno, except when the
2835 * fsid is != to that of the directory. For that
2836 * case, generate a fake fileno that is not the same.
2838 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID);
2843 * Joy, oh joy. For V4 we get to hand craft '.' and '..'.
2845 if (uiop->uio_offset == 0) {
2846 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp);
2847 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2848 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
2849 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2850 (void) nfsrv_putattrbit(nd, &attrbits);
2851 error = nfscl_request(nd, vp, p, cred, stuff);
2854 dotfileid = 0; /* Fake out the compiler. */
2855 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
2856 error = nfsm_loadattr(nd, &nfsva);
2859 dotfileid = nfsva.na_fileid;
2861 if (nd->nd_repstat == 0) {
2862 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2863 len = fxdr_unsigned(int, *(tl + 4));
2864 if (len > 0 && len <= NFSX_V4FHMAX)
2865 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
2869 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
2870 nfsva.na_mntonfileno = 0xffffffff;
2871 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
2872 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
2873 NULL, NULL, NULL, p, cred);
2875 dotdotfileid = dotfileid;
2876 } else if (gotmnton) {
2877 if (nfsva.na_mntonfileno != 0xffffffff)
2878 dotdotfileid = nfsva.na_mntonfileno;
2880 dotdotfileid = nfsva.na_fileid;
2881 } else if (nfsva.na_filesid[0] ==
2882 dnp->n_vattr.na_filesid[0] &&
2883 nfsva.na_filesid[1] ==
2884 dnp->n_vattr.na_filesid[1]) {
2885 dotdotfileid = nfsva.na_fileid;
2889 } while (fakefileno ==
2891 dotdotfileid = fakefileno;
2894 } else if (nd->nd_repstat == NFSERR_NOENT) {
2896 * Lookupp returns NFSERR_NOENT when we are
2897 * at the root, so just use the current dir.
2900 dotdotfileid = dotfileid;
2902 error = nd->nd_repstat;
2904 mbuf_freem(nd->nd_mrep);
2908 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
2909 dp->d_type = DT_DIR;
2910 dp->d_fileno = dotfileid;
2912 dp->d_name[0] = '.';
2913 dp->d_name[1] = '\0';
2914 dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
2916 * Just make these offset cookie 0.
2918 tl = (u_int32_t *)&dp->d_name[4];
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 *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
2927 dp->d_type = DT_DIR;
2928 dp->d_fileno = dotdotfileid;
2930 dp->d_name[0] = '.';
2931 dp->d_name[1] = '.';
2932 dp->d_name[2] = '\0';
2933 dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
2935 * Just make these offset cookie 0.
2937 tl = (u_int32_t *)&dp->d_name[4];
2940 blksiz += dp->d_reclen;
2941 uio_uio_resid_add(uiop, -(dp->d_reclen));
2942 uiop->uio_offset += dp->d_reclen;
2943 uio_iov_base_add(uiop, dp->d_reclen);
2944 uio_iov_len_add(uiop, -(dp->d_reclen));
2946 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_RDATTRERROR);
2948 reqsize = 5 * NFSX_UNSIGNED;
2953 * Loop around doing readdir rpc's of size readsize.
2954 * The stopping criteria is EOF or buffer full.
2956 while (more_dirs && bigenough) {
2958 NFSCL_REQSTART(nd, NFSPROC_READDIR, vp);
2959 if (nd->nd_flag & ND_NFSV2) {
2960 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2961 *tl++ = cookie.lval[1];
2962 *tl = txdr_unsigned(readsize);
2964 NFSM_BUILD(tl, u_int32_t *, reqsize);
2965 *tl++ = cookie.lval[0];
2966 *tl++ = cookie.lval[1];
2967 if (cookie.qval == 0) {
2972 *tl++ = dnp->n_cookieverf.nfsuquad[0];
2973 *tl++ = dnp->n_cookieverf.nfsuquad[1];
2976 if (nd->nd_flag & ND_NFSV4) {
2977 *tl++ = txdr_unsigned(readsize);
2978 *tl = txdr_unsigned(readsize);
2979 (void) nfsrv_putattrbit(nd, &attrbits);
2980 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2981 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2982 (void) nfsrv_putattrbit(nd, &dattrbits);
2984 *tl = txdr_unsigned(readsize);
2987 error = nfscl_request(nd, vp, p, cred, stuff);
2990 if (!(nd->nd_flag & ND_NFSV2)) {
2991 if (nd->nd_flag & ND_NFSV3)
2992 error = nfscl_postop_attr(nd, nap, attrflagp,
2994 if (!nd->nd_repstat && !error) {
2995 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2997 dnp->n_cookieverf.nfsuquad[0] = *tl++;
2998 dnp->n_cookieverf.nfsuquad[1] = *tl;
3002 if (nd->nd_repstat || error) {
3004 error = nd->nd_repstat;
3007 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3008 more_dirs = fxdr_unsigned(int, *tl);
3012 /* loop through the dir entries, doctoring them to 4bsd form */
3013 while (more_dirs && bigenough) {
3014 if (nd->nd_flag & ND_NFSV4) {
3015 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3016 ncookie.lval[0] = *tl++;
3017 ncookie.lval[1] = *tl++;
3018 len = fxdr_unsigned(int, *tl);
3019 } else if (nd->nd_flag & ND_NFSV3) {
3020 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3021 nfsva.na_fileid = fxdr_hyper(tl);
3023 len = fxdr_unsigned(int, *tl);
3025 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
3027 fxdr_unsigned(long, *tl++);
3028 len = fxdr_unsigned(int, *tl);
3030 if (len <= 0 || len > NFS_MAXNAMLEN) {
3034 tlen = NFSM_RNDUP(len);
3036 tlen += 4; /* To ensure null termination */
3037 left = DIRBLKSIZ - blksiz;
3038 if ((int)(tlen + DIRHDSIZ + NFSX_HYPER) > left) {
3039 dp->d_reclen += left;
3040 uio_iov_base_add(uiop, left);
3041 uio_iov_len_add(uiop, -(left));
3042 uio_uio_resid_add(uiop, -(left));
3043 uiop->uio_offset += left;
3046 if ((int)(tlen + DIRHDSIZ + NFSX_HYPER) > uio_uio_resid(uiop))
3049 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
3051 dp->d_reclen = tlen + DIRHDSIZ + NFSX_HYPER;
3052 dp->d_type = DT_UNKNOWN;
3053 blksiz += dp->d_reclen;
3054 if (blksiz == DIRBLKSIZ)
3056 uio_uio_resid_add(uiop, -(DIRHDSIZ));
3057 uiop->uio_offset += DIRHDSIZ;
3058 uio_iov_base_add(uiop, DIRHDSIZ);
3059 uio_iov_len_add(uiop, -(DIRHDSIZ));
3060 error = nfsm_mbufuio(nd, uiop, len);
3063 cp = CAST_DOWN(caddr_t, uio_iov_base(uiop));
3065 *cp = '\0'; /* null terminate */
3066 cp += tlen; /* points to cookie storage */
3067 tl2 = (u_int32_t *)cp;
3068 uio_iov_base_add(uiop, (tlen + NFSX_HYPER));
3069 uio_iov_len_add(uiop, -(tlen + NFSX_HYPER));
3070 uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER));
3071 uiop->uio_offset += (tlen + NFSX_HYPER);
3073 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
3077 if (nd->nd_flag & ND_NFSV4) {
3079 nfsva.na_mntonfileno = 0xffffffff;
3080 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
3081 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
3082 NULL, NULL, &rderr, p, cred);
3085 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3086 } else if (nd->nd_flag & ND_NFSV3) {
3087 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3088 ncookie.lval[0] = *tl++;
3089 ncookie.lval[1] = *tl++;
3091 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
3092 ncookie.lval[0] = 0;
3093 ncookie.lval[1] = *tl++;
3096 if (nd->nd_flag & ND_NFSV4) {
3101 if (nfsva.na_mntonfileno != 0xffffffff)
3102 dp->d_fileno = nfsva.na_mntonfileno;
3104 dp->d_fileno = nfsva.na_fileid;
3105 } else if (nfsva.na_filesid[0] ==
3106 dnp->n_vattr.na_filesid[0] &&
3107 nfsva.na_filesid[1] ==
3108 dnp->n_vattr.na_filesid[1]) {
3109 dp->d_fileno = nfsva.na_fileid;
3113 } while (fakefileno ==
3115 dp->d_fileno = fakefileno;
3117 dp->d_type = vtonfs_dtype(nfsva.na_type);
3120 dp->d_fileno = nfsva.na_fileid;
3122 *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] =
3124 *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] =
3127 more_dirs = fxdr_unsigned(int, *tl);
3130 * If at end of rpc data, get the eof boolean
3133 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3134 eof = fxdr_unsigned(int, *tl);
3137 if (nd->nd_flag & ND_NFSV4) {
3138 error = nfscl_postop_attr(nd, nap, attrflagp,
3144 mbuf_freem(nd->nd_mrep);
3148 * Fill last record, iff any, out to a multiple of DIRBLKSIZ
3149 * by increasing d_reclen for the last record.
3152 left = DIRBLKSIZ - blksiz;
3153 dp->d_reclen += left;
3154 uio_iov_base_add(uiop, left);
3155 uio_iov_len_add(uiop, -(left));
3156 uio_uio_resid_add(uiop, -(left));
3157 uiop->uio_offset += left;
3161 * If returning no data, assume end of file.
3162 * If not bigenough, return not end of file, since you aren't
3163 * returning all the data
3164 * Otherwise, return the eof flag from the server.
3167 if (tresid == ((size_t)(uio_uio_resid(uiop))))
3169 else if (!bigenough)
3176 * Add extra empty records to any remaining DIRBLKSIZ chunks.
3178 while (uio_uio_resid(uiop) > 0 && ((size_t)(uio_uio_resid(uiop))) != tresid) {
3179 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
3180 dp->d_type = DT_UNKNOWN;
3183 dp->d_name[0] = '\0';
3184 tl = (u_int32_t *)&dp->d_name[4];
3185 *tl++ = cookie.lval[0];
3186 *tl = cookie.lval[1];
3187 dp->d_reclen = DIRBLKSIZ;
3188 uio_iov_base_add(uiop, DIRBLKSIZ);
3189 uio_iov_len_add(uiop, -(DIRBLKSIZ));
3190 uio_uio_resid_add(uiop, -(DIRBLKSIZ));
3191 uiop->uio_offset += DIRBLKSIZ;
3195 if (nd->nd_mrep != NULL)
3196 mbuf_freem(nd->nd_mrep);
3202 * NFS V3 readdir plus RPC. Used in place of nfsrpc_readdir().
3203 * (Also used for NFS V4 when mount flag set.)
3204 * (ditto above w.r.t. multiple of DIRBLKSIZ, etc.)
3207 nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
3208 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
3209 int *eofp, void *stuff)
3212 struct dirent *dp = NULL;
3214 vnode_t newvp = NULLVP;
3215 struct nfsrv_descript nfsd, *nd = &nfsd;
3216 struct nameidata nami, *ndp = &nami;
3217 struct componentname *cnp = &ndp->ni_cnd;
3218 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
3219 struct nfsnode *dnp = VTONFS(vp), *np;
3220 struct nfsvattr nfsva;
3222 nfsquad_t cookie, ncookie;
3223 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
3224 int attrflag, tryformoredirs = 1, eof = 0, gotmnton = 0;
3225 int isdotdot = 0, unlocknewvp = 0;
3226 long dotfileid, dotdotfileid = 0, fileno = 0;
3228 nfsattrbit_t attrbits, dattrbits;
3230 u_int32_t *tl2 = NULL, fakefileno = 0xffffffff, rderr;
3231 struct timespec dctime;
3233 KASSERT(uiop->uio_iovcnt == 1 &&
3234 (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0,
3235 ("nfs readdirplusrpc bad uio"));
3236 timespecclear(&dctime);
3242 cookie.lval[0] = cookiep->nfsuquad[0];
3243 cookie.lval[1] = cookiep->nfsuquad[1];
3244 tresid = uio_uio_resid(uiop);
3247 * For NFSv4, first create the "." and ".." entries.
3249 if (NFSHASNFSV4(nmp)) {
3250 NFSGETATTR_ATTRBIT(&dattrbits);
3251 NFSZERO_ATTRBIT(&attrbits);
3252 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID);
3253 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
3254 NFSATTRBIT_MOUNTEDONFILEID)) {
3255 NFSSETBIT_ATTRBIT(&attrbits,
3256 NFSATTRBIT_MOUNTEDONFILEID);
3260 * Must fake it. Use the fileno, except when the
3261 * fsid is != to that of the directory. For that
3262 * case, generate a fake fileno that is not the same.
3264 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID);
3269 * Joy, oh joy. For V4 we get to hand craft '.' and '..'.
3271 if (uiop->uio_offset == 0) {
3272 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp);
3273 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3274 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
3275 *tl = txdr_unsigned(NFSV4OP_GETATTR);
3276 (void) nfsrv_putattrbit(nd, &attrbits);
3277 error = nfscl_request(nd, vp, p, cred, stuff);
3280 dotfileid = 0; /* Fake out the compiler. */
3281 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
3282 error = nfsm_loadattr(nd, &nfsva);
3285 dctime = nfsva.na_ctime;
3286 dotfileid = nfsva.na_fileid;
3288 if (nd->nd_repstat == 0) {
3289 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
3290 len = fxdr_unsigned(int, *(tl + 4));
3291 if (len > 0 && len <= NFSX_V4FHMAX)
3292 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
3296 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
3297 nfsva.na_mntonfileno = 0xffffffff;
3298 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
3299 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
3300 NULL, NULL, NULL, p, cred);
3302 dotdotfileid = dotfileid;
3303 } else if (gotmnton) {
3304 if (nfsva.na_mntonfileno != 0xffffffff)
3305 dotdotfileid = nfsva.na_mntonfileno;
3307 dotdotfileid = nfsva.na_fileid;
3308 } else if (nfsva.na_filesid[0] ==
3309 dnp->n_vattr.na_filesid[0] &&
3310 nfsva.na_filesid[1] ==
3311 dnp->n_vattr.na_filesid[1]) {
3312 dotdotfileid = nfsva.na_fileid;
3316 } while (fakefileno ==
3318 dotdotfileid = fakefileno;
3321 } else if (nd->nd_repstat == NFSERR_NOENT) {
3323 * Lookupp returns NFSERR_NOENT when we are
3324 * at the root, so just use the current dir.
3327 dotdotfileid = dotfileid;
3329 error = nd->nd_repstat;
3331 mbuf_freem(nd->nd_mrep);
3335 dp = (struct dirent *)uio_iov_base(uiop);
3336 dp->d_type = DT_DIR;
3337 dp->d_fileno = dotfileid;
3339 dp->d_name[0] = '.';
3340 dp->d_name[1] = '\0';
3341 dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
3343 * Just make these offset cookie 0.
3345 tl = (u_int32_t *)&dp->d_name[4];
3348 blksiz += dp->d_reclen;
3349 uio_uio_resid_add(uiop, -(dp->d_reclen));
3350 uiop->uio_offset += dp->d_reclen;
3351 uio_iov_base_add(uiop, dp->d_reclen);
3352 uio_iov_len_add(uiop, -(dp->d_reclen));
3353 dp = (struct dirent *)uio_iov_base(uiop);
3354 dp->d_type = DT_DIR;
3355 dp->d_fileno = dotdotfileid;
3357 dp->d_name[0] = '.';
3358 dp->d_name[1] = '.';
3359 dp->d_name[2] = '\0';
3360 dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
3362 * Just make these offset cookie 0.
3364 tl = (u_int32_t *)&dp->d_name[4];
3367 blksiz += dp->d_reclen;
3368 uio_uio_resid_add(uiop, -(dp->d_reclen));
3369 uiop->uio_offset += dp->d_reclen;
3370 uio_iov_base_add(uiop, dp->d_reclen);
3371 uio_iov_len_add(uiop, -(dp->d_reclen));
3373 NFSREADDIRPLUS_ATTRBIT(&attrbits);
3375 NFSSETBIT_ATTRBIT(&attrbits,
3376 NFSATTRBIT_MOUNTEDONFILEID);
3380 * Loop around doing readdir rpc's of size nm_readdirsize.
3381 * The stopping criteria is EOF or buffer full.
3383 while (more_dirs && bigenough) {
3385 NFSCL_REQSTART(nd, NFSPROC_READDIRPLUS, vp);
3386 NFSM_BUILD(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
3387 *tl++ = cookie.lval[0];
3388 *tl++ = cookie.lval[1];
3389 if (cookie.qval == 0) {
3394 *tl++ = dnp->n_cookieverf.nfsuquad[0];
3395 *tl++ = dnp->n_cookieverf.nfsuquad[1];
3398 *tl++ = txdr_unsigned(nmp->nm_readdirsize);
3399 *tl = txdr_unsigned(nmp->nm_readdirsize);
3400 if (nd->nd_flag & ND_NFSV4) {
3401 (void) nfsrv_putattrbit(nd, &attrbits);
3402 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3403 *tl = txdr_unsigned(NFSV4OP_GETATTR);
3404 (void) nfsrv_putattrbit(nd, &dattrbits);
3406 error = nfscl_request(nd, vp, p, cred, stuff);
3409 if (nd->nd_flag & ND_NFSV3)
3410 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3411 if (nd->nd_repstat || error) {
3413 error = nd->nd_repstat;
3416 if ((nd->nd_flag & ND_NFSV3) != 0 && *attrflagp != 0)
3417 dctime = nap->na_ctime;
3418 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3420 dnp->n_cookieverf.nfsuquad[0] = *tl++;
3421 dnp->n_cookieverf.nfsuquad[1] = *tl++;
3423 more_dirs = fxdr_unsigned(int, *tl);
3427 /* loop through the dir entries, doctoring them to 4bsd form */
3428 while (more_dirs && bigenough) {
3429 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3430 if (nd->nd_flag & ND_NFSV4) {
3431 ncookie.lval[0] = *tl++;
3432 ncookie.lval[1] = *tl++;
3434 fileno = fxdr_unsigned(long, *++tl);
3437 len = fxdr_unsigned(int, *tl);
3438 if (len <= 0 || len > NFS_MAXNAMLEN) {
3442 tlen = NFSM_RNDUP(len);
3444 tlen += 4; /* To ensure null termination */
3445 left = DIRBLKSIZ - blksiz;
3446 if ((tlen + DIRHDSIZ + NFSX_HYPER) > left) {
3447 dp->d_reclen += left;
3448 uio_iov_base_add(uiop, left);
3449 uio_iov_len_add(uiop, -(left));
3450 uio_uio_resid_add(uiop, -(left));
3451 uiop->uio_offset += left;
3454 if ((tlen + DIRHDSIZ + NFSX_HYPER) > uio_uio_resid(uiop))
3457 dp = (struct dirent *)uio_iov_base(uiop);
3459 dp->d_reclen = tlen + DIRHDSIZ + NFSX_HYPER;
3460 dp->d_type = DT_UNKNOWN;
3461 blksiz += dp->d_reclen;
3462 if (blksiz == DIRBLKSIZ)
3464 uio_uio_resid_add(uiop, -(DIRHDSIZ));
3465 uiop->uio_offset += DIRHDSIZ;
3466 uio_iov_base_add(uiop, DIRHDSIZ);
3467 uio_iov_len_add(uiop, -(DIRHDSIZ));
3468 cnp->cn_nameptr = uio_iov_base(uiop);
3469 cnp->cn_namelen = len;
3471 error = nfsm_mbufuio(nd, uiop, len);
3474 cp = uio_iov_base(uiop);
3477 cp += tlen; /* points to cookie storage */
3478 tl2 = (u_int32_t *)cp;
3479 if (len == 2 && cnp->cn_nameptr[0] == '.' &&
3480 cnp->cn_nameptr[1] == '.')
3484 uio_iov_base_add(uiop, (tlen + NFSX_HYPER));
3485 uio_iov_len_add(uiop, -(tlen + NFSX_HYPER));
3486 uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER));
3487 uiop->uio_offset += (tlen + NFSX_HYPER);
3489 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
3494 if (nd->nd_flag & ND_NFSV3) {
3495 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3496 ncookie.lval[0] = *tl++;
3497 ncookie.lval[1] = *tl++;
3498 attrflag = fxdr_unsigned(int, *tl);
3500 error = nfsm_loadattr(nd, &nfsva);
3504 NFSM_DISSECT(tl,u_int32_t *,NFSX_UNSIGNED);
3506 error = nfsm_getfh(nd, &nfhp);
3510 if (!attrflag && nfhp != NULL) {
3511 FREE((caddr_t)nfhp, M_NFSFH);
3516 nfsva.na_mntonfileno = 0xffffffff;
3517 error = nfsv4_loadattr(nd, NULL, &nfsva, &nfhp,
3518 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
3519 NULL, NULL, &rderr, p, cred);
3525 if (nd->nd_flag & ND_NFSV4) {
3528 } else if (gotmnton) {
3529 if (nfsva.na_mntonfileno != 0xffffffff)
3530 dp->d_fileno = nfsva.na_mntonfileno;
3532 dp->d_fileno = nfsva.na_fileid;
3533 } else if (nfsva.na_filesid[0] ==
3534 dnp->n_vattr.na_filesid[0] &&
3535 nfsva.na_filesid[1] ==
3536 dnp->n_vattr.na_filesid[1]) {
3537 dp->d_fileno = nfsva.na_fileid;
3541 } while (fakefileno ==
3543 dp->d_fileno = fakefileno;
3546 dp->d_fileno = fileno;
3548 *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] =
3550 *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] =
3554 if (NFSRV_CMPFH(nfhp->nfh_fh, nfhp->nfh_len,
3555 dnp->n_fhp->nfh_fh, dnp->n_fhp->nfh_len)) {
3559 FREE((caddr_t)nfhp, M_NFSFH);
3561 } else if (isdotdot != 0) {
3563 * Skip doing a nfscl_nget() call for "..".
3564 * There's a race between acquiring the nfs
3565 * node here and lookups that look for the
3566 * directory being read (in the parent).
3567 * It would try to get a lock on ".." here,
3568 * owning the lock on the directory being
3569 * read. Lookup will hold the lock on ".."
3570 * and try to acquire the lock on the
3571 * directory being read.
3572 * If the directory is unlocked/relocked,
3573 * then there is a LOR with the buflock
3576 free(nfhp, M_NFSFH);
3578 error = nfscl_nget(vnode_mount(vp), vp,
3579 nfhp, cnp, p, &np, NULL, LK_EXCLUSIVE);
3586 if (newvp != NULLVP) {
3587 error = nfscl_loadattrcache(&newvp,
3588 &nfsva, NULL, NULL, 0, 0);
3597 vtonfs_dtype(np->n_vattr.na_type);
3599 NFSCNHASH(cnp, HASHINIT);
3600 if (cnp->cn_namelen <= NCHNAMLEN &&
3601 (newvp->v_type != VDIR ||
3602 dctime.tv_sec != 0)) {
3603 cache_enter_time(ndp->ni_dvp,
3606 newvp->v_type != VDIR ? NULL :
3616 } else if (nfhp != NULL) {
3617 FREE((caddr_t)nfhp, M_NFSFH);
3619 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3620 more_dirs = fxdr_unsigned(int, *tl);
3623 * If at end of rpc data, get the eof boolean
3626 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3627 eof = fxdr_unsigned(int, *tl);
3630 if (nd->nd_flag & ND_NFSV4) {
3631 error = nfscl_postop_attr(nd, nap, attrflagp,
3637 mbuf_freem(nd->nd_mrep);
3641 * Fill last record, iff any, out to a multiple of DIRBLKSIZ
3642 * by increasing d_reclen for the last record.
3645 left = DIRBLKSIZ - blksiz;
3646 dp->d_reclen += left;
3647 uio_iov_base_add(uiop, left);
3648 uio_iov_len_add(uiop, -(left));
3649 uio_uio_resid_add(uiop, -(left));
3650 uiop->uio_offset += left;
3654 * If returning no data, assume end of file.
3655 * If not bigenough, return not end of file, since you aren't
3656 * returning all the data
3657 * Otherwise, return the eof flag from the server.
3660 if (tresid == uio_uio_resid(uiop))
3662 else if (!bigenough)
3669 * Add extra empty records to any remaining DIRBLKSIZ chunks.
3671 while (uio_uio_resid(uiop) > 0 && uio_uio_resid(uiop) != tresid) {
3672 dp = (struct dirent *)uio_iov_base(uiop);
3673 dp->d_type = DT_UNKNOWN;
3676 dp->d_name[0] = '\0';
3677 tl = (u_int32_t *)&dp->d_name[4];
3678 *tl++ = cookie.lval[0];
3679 *tl = cookie.lval[1];
3680 dp->d_reclen = DIRBLKSIZ;
3681 uio_iov_base_add(uiop, DIRBLKSIZ);
3682 uio_iov_len_add(uiop, -(DIRBLKSIZ));
3683 uio_uio_resid_add(uiop, -(DIRBLKSIZ));
3684 uiop->uio_offset += DIRBLKSIZ;
3688 if (nd->nd_mrep != NULL)
3689 mbuf_freem(nd->nd_mrep);
3698 nfsrpc_commit(vnode_t vp, u_quad_t offset, int cnt, struct ucred *cred,
3699 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
3702 struct nfsrv_descript nfsd, *nd = &nfsd;
3703 nfsattrbit_t attrbits;
3705 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
3708 NFSCL_REQSTART(nd, NFSPROC_COMMIT, vp);
3709 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3710 txdr_hyper(offset, tl);
3712 *tl = txdr_unsigned(cnt);
3713 if (nd->nd_flag & ND_NFSV4) {
3715 * And do a Getattr op.
3717 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3718 *tl = txdr_unsigned(NFSV4OP_GETATTR);
3719 NFSGETATTR_ATTRBIT(&attrbits);
3720 (void) nfsrv_putattrbit(nd, &attrbits);
3722 error = nfscl_request(nd, vp, p, cred, stuff);
3725 error = nfscl_wcc_data(nd, vp, nap, attrflagp, NULL, stuff);
3726 if (!error && !nd->nd_repstat) {
3727 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
3729 if (NFSBCMP(nmp->nm_verf, tl, NFSX_VERF)) {
3730 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
3731 nd->nd_repstat = NFSERR_STALEWRITEVERF;
3734 if (nd->nd_flag & ND_NFSV4)
3735 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3738 if (!error && nd->nd_repstat)
3739 error = nd->nd_repstat;
3740 mbuf_freem(nd->nd_mrep);
3745 * NFS byte range lock rpc.
3746 * (Mostly just calls one of the three lower level RPC routines.)
3749 nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
3750 int reclaim, struct ucred *cred, NFSPROC_T *p, void *id, int flags)
3752 struct nfscllockowner *lp;
3753 struct nfsclclient *clp;
3755 struct nfsrv_descript nfsd, *nd = &nfsd;
3756 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
3759 u_int32_t clidrev = 0;
3760 int error = 0, newone = 0, expireret = 0, retrycnt, donelocally;
3764 * Convert the flock structure into a start and end and do POSIX
3767 switch (fl->l_whence) {
3771 * Caller is responsible for adding any necessary offset
3772 * when SEEK_CUR is used.
3774 start = fl->l_start;
3778 start = size + fl->l_start;
3779 off = size + fl->l_start;
3786 if (fl->l_len != 0) {
3787 end = start + fl->l_len - 1;
3798 if (op == F_GETLK) {
3799 error = nfscl_getcl(vnode_mount(vp), cred, p, 1, &clp);
3802 error = nfscl_lockt(vp, clp, off, len, fl, p, id, flags);
3804 clidrev = clp->nfsc_clientidrev;
3805 error = nfsrpc_lockt(nd, vp, clp, off, len, fl, cred,
3807 } else if (error == -1) {
3810 nfscl_clientrelease(clp);
3811 } else if (op == F_UNLCK && fl->l_type == F_UNLCK) {
3813 * We must loop around for all lockowner cases.
3816 error = nfscl_getcl(vnode_mount(vp), cred, p, 1, &clp);
3820 error = nfscl_relbytelock(vp, off, len, cred, p, callcnt,
3821 clp, id, flags, &lp, &dorpc);
3823 * If it returns a NULL lp, we're done.
3827 nfscl_clientrelease(clp);
3829 nfscl_releasealllocks(clp, vp, p, id, flags);
3832 if (nmp->nm_clp != NULL)
3833 clidrev = nmp->nm_clp->nfsc_clientidrev;
3837 * If the server doesn't support Posix lock semantics,
3838 * only allow locks on the entire file, since it won't
3839 * handle overlapping byte ranges.
3840 * There might still be a problem when a lock
3841 * upgrade/downgrade (read<->write) occurs, since the
3842 * server "might" expect an unlock first?
3844 if (dorpc && (lp->nfsl_open->nfso_posixlock ||
3845 (off == 0 && len == NFS64BITSSET))) {
3847 * Since the lock records will go away, we must
3848 * wait for grace and delay here.
3851 error = nfsrpc_locku(nd, nmp, lp, off, len,
3852 NFSV4LOCKT_READ, cred, p, 0);
3853 if ((nd->nd_repstat == NFSERR_GRACE ||
3854 nd->nd_repstat == NFSERR_DELAY) &&
3856 (void) nfs_catnap(PZERO, (int)nd->nd_repstat,
3858 } while ((nd->nd_repstat == NFSERR_GRACE ||
3859 nd->nd_repstat == NFSERR_DELAY) && error == 0);
3862 } while (error == 0 && nd->nd_repstat == 0);
3863 nfscl_releasealllocks(clp, vp, p, id, flags);
3864 } else if (op == F_SETLK) {
3865 error = nfscl_getbytelock(vp, off, len, fl->l_type, cred, p,
3866 NULL, 0, id, flags, NULL, NULL, &lp, &newone, &donelocally);
3867 if (error || donelocally) {
3870 if (nmp->nm_clp != NULL)
3871 clidrev = nmp->nm_clp->nfsc_clientidrev;
3874 nfhp = VTONFS(vp)->n_fhp;
3875 if (!lp->nfsl_open->nfso_posixlock &&
3876 (off != 0 || len != NFS64BITSSET)) {
3879 error = nfsrpc_lock(nd, nmp, vp, nfhp->nfh_fh,
3880 nfhp->nfh_len, lp, newone, reclaim, off,
3881 len, fl->l_type, cred, p, 0);
3884 error = nd->nd_repstat;
3885 nfscl_lockrelease(lp, error, newone);
3890 error = nd->nd_repstat;
3891 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
3892 error == NFSERR_STALEDONTRECOVER ||
3893 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY ||
3894 error == NFSERR_BADSESSION) {
3895 (void) nfs_catnap(PZERO, error, "nfs_advlock");
3896 } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID)
3898 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
3901 } while (error == NFSERR_GRACE ||
3902 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY ||
3903 error == NFSERR_STALEDONTRECOVER || error == NFSERR_STALESTATEID ||
3904 error == NFSERR_BADSESSION ||
3905 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
3906 expireret == 0 && clidrev != 0 && retrycnt < 4));
3907 if (error && retrycnt >= 4)
3913 * The lower level routine for the LockT case.
3916 nfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp,
3917 struct nfsclclient *clp, u_int64_t off, u_int64_t len, struct flock *fl,
3918 struct ucred *cred, NFSPROC_T *p, void *id, int flags)
3921 int error, type, size;
3922 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
3924 struct nfsmount *nmp;
3925 struct nfsclsession *tsep;
3927 nmp = VFSTONFS(vp->v_mount);
3928 NFSCL_REQSTART(nd, NFSPROC_LOCKT, vp);
3929 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
3930 if (fl->l_type == F_RDLCK)
3931 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
3933 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
3934 txdr_hyper(off, tl);
3936 txdr_hyper(len, tl);
3938 tsep = nfsmnt_mdssession(nmp);
3939 *tl++ = tsep->nfsess_clientid.lval[0];
3940 *tl = tsep->nfsess_clientid.lval[1];
3941 nfscl_filllockowner(id, own, flags);
3943 NFSBCOPY(np->n_fhp->nfh_fh, &own[NFSV4CL_LOCKNAMELEN],
3944 np->n_fhp->nfh_len);
3945 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + np->n_fhp->nfh_len);
3946 error = nfscl_request(nd, vp, p, cred, NULL);
3949 if (nd->nd_repstat == 0) {
3950 fl->l_type = F_UNLCK;
3951 } else if (nd->nd_repstat == NFSERR_DENIED) {
3953 fl->l_whence = SEEK_SET;
3954 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
3955 fl->l_start = fxdr_hyper(tl);
3957 len = fxdr_hyper(tl);
3959 if (len == NFS64BITSSET)
3963 type = fxdr_unsigned(int, *tl++);
3964 if (type == NFSV4LOCKT_WRITE)
3965 fl->l_type = F_WRLCK;
3967 fl->l_type = F_RDLCK;
3969 * XXX For now, I have no idea what to do with the
3970 * conflicting lock_owner, so I'll just set the pid == 0
3971 * and skip over the lock_owner.
3973 fl->l_pid = (pid_t)0;
3975 size = fxdr_unsigned(int, *tl);
3976 if (size < 0 || size > NFSV4_OPAQUELIMIT)
3979 error = nfsm_advance(nd, NFSM_RNDUP(size), -1);
3980 } else if (nd->nd_repstat == NFSERR_STALECLIENTID)
3981 nfscl_initiate_recovery(clp);
3983 mbuf_freem(nd->nd_mrep);
3988 * Lower level function that performs the LockU RPC.
3991 nfsrpc_locku(struct nfsrv_descript *nd, struct nfsmount *nmp,
3992 struct nfscllockowner *lp, u_int64_t off, u_int64_t len,
3993 u_int32_t type, struct ucred *cred, NFSPROC_T *p, int syscred)
3998 nfscl_reqstart(nd, NFSPROC_LOCKU, nmp, lp->nfsl_open->nfso_fh,
3999 lp->nfsl_open->nfso_fhlen, NULL, NULL);
4000 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
4001 *tl++ = txdr_unsigned(type);
4002 *tl = txdr_unsigned(lp->nfsl_seqid);
4003 if (nfstest_outofseq &&
4004 (arc4random() % nfstest_outofseq) == 0)
4005 *tl = txdr_unsigned(lp->nfsl_seqid + 1);
4007 if (NFSHASNFSV4N(nmp))
4010 *tl++ = lp->nfsl_stateid.seqid;
4011 *tl++ = lp->nfsl_stateid.other[0];
4012 *tl++ = lp->nfsl_stateid.other[1];
4013 *tl++ = lp->nfsl_stateid.other[2];
4014 txdr_hyper(off, tl);
4016 txdr_hyper(len, tl);
4018 nd->nd_flag |= ND_USEGSSNAME;
4019 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4020 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4021 NFSCL_INCRSEQID(lp->nfsl_seqid, nd);
4024 if (nd->nd_repstat == 0) {
4025 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
4026 lp->nfsl_stateid.seqid = *tl++;
4027 lp->nfsl_stateid.other[0] = *tl++;
4028 lp->nfsl_stateid.other[1] = *tl++;
4029 lp->nfsl_stateid.other[2] = *tl;
4030 } else if (nd->nd_repstat == NFSERR_STALESTATEID)
4031 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp);
4033 mbuf_freem(nd->nd_mrep);
4038 * The actual Lock RPC.
4041 nfsrpc_lock(struct nfsrv_descript *nd, struct nfsmount *nmp, vnode_t vp,
4042 u_int8_t *nfhp, int fhlen, struct nfscllockowner *lp, int newone,
4043 int reclaim, u_int64_t off, u_int64_t len, short type, struct ucred *cred,
4044 NFSPROC_T *p, int syscred)
4048 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
4049 struct nfsclsession *tsep;
4051 nfscl_reqstart(nd, NFSPROC_LOCK, nmp, nfhp, fhlen, NULL, NULL);
4052 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
4053 if (type == F_RDLCK)
4054 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
4056 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
4057 *tl++ = txdr_unsigned(reclaim);
4058 txdr_hyper(off, tl);
4060 txdr_hyper(len, tl);
4064 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID +
4065 2 * NFSX_UNSIGNED + NFSX_HYPER);
4066 *tl++ = txdr_unsigned(lp->nfsl_open->nfso_own->nfsow_seqid);
4067 if (NFSHASNFSV4N(nmp))
4070 *tl++ = lp->nfsl_open->nfso_stateid.seqid;
4071 *tl++ = lp->nfsl_open->nfso_stateid.other[0];
4072 *tl++ = lp->nfsl_open->nfso_stateid.other[1];
4073 *tl++ = lp->nfsl_open->nfso_stateid.other[2];
4074 *tl++ = txdr_unsigned(lp->nfsl_seqid);
4075 tsep = nfsmnt_mdssession(nmp);
4076 *tl++ = tsep->nfsess_clientid.lval[0];
4077 *tl = tsep->nfsess_clientid.lval[1];
4078 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN);
4079 NFSBCOPY(nfhp, &own[NFSV4CL_LOCKNAMELEN], fhlen);
4080 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen);
4083 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
4084 if (NFSHASNFSV4N(nmp))
4087 *tl++ = lp->nfsl_stateid.seqid;
4088 *tl++ = lp->nfsl_stateid.other[0];
4089 *tl++ = lp->nfsl_stateid.other[1];
4090 *tl++ = lp->nfsl_stateid.other[2];
4091 *tl = txdr_unsigned(lp->nfsl_seqid);
4092 if (nfstest_outofseq &&
4093 (arc4random() % nfstest_outofseq) == 0)
4094 *tl = txdr_unsigned(lp->nfsl_seqid + 1);
4097 nd->nd_flag |= ND_USEGSSNAME;
4098 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
4099 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4103 NFSCL_INCRSEQID(lp->nfsl_open->nfso_own->nfsow_seqid, nd);
4104 NFSCL_INCRSEQID(lp->nfsl_seqid, nd);
4105 if (nd->nd_repstat == 0) {
4106 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
4107 lp->nfsl_stateid.seqid = *tl++;
4108 lp->nfsl_stateid.other[0] = *tl++;
4109 lp->nfsl_stateid.other[1] = *tl++;
4110 lp->nfsl_stateid.other[2] = *tl;
4111 } else if (nd->nd_repstat == NFSERR_DENIED) {
4112 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
4113 size = fxdr_unsigned(int, *(tl + 7));
4114 if (size < 0 || size > NFSV4_OPAQUELIMIT)
4117 error = nfsm_advance(nd, NFSM_RNDUP(size), -1);
4118 } else if (nd->nd_repstat == NFSERR_STALESTATEID)
4119 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp);
4121 mbuf_freem(nd->nd_mrep);
4127 * (always called with the vp for the mount point)
4130 nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp,
4131 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
4134 u_int32_t *tl = NULL;
4135 struct nfsrv_descript nfsd, *nd = &nfsd;
4136 struct nfsmount *nmp;
4137 nfsattrbit_t attrbits;
4141 nmp = VFSTONFS(vnode_mount(vp));
4142 if (NFSHASNFSV4(nmp)) {
4144 * For V4, you actually do a getattr.
4146 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
4147 NFSSTATFS_GETATTRBIT(&attrbits);
4148 (void) nfsrv_putattrbit(nd, &attrbits);
4149 nd->nd_flag |= ND_USEGSSNAME;
4150 error = nfscl_request(nd, vp, p, cred, stuff);
4153 if (nd->nd_repstat == 0) {
4154 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
4155 NULL, NULL, sbp, fsp, NULL, 0, NULL, NULL, NULL, p,
4158 nmp->nm_fsid[0] = nap->na_filesid[0];
4159 nmp->nm_fsid[1] = nap->na_filesid[1];
4160 NFSSETHASSETFSID(nmp);
4164 error = nd->nd_repstat;
4169 NFSCL_REQSTART(nd, NFSPROC_FSSTAT, vp);
4170 error = nfscl_request(nd, vp, p, cred, stuff);
4173 if (nd->nd_flag & ND_NFSV3) {
4174 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
4178 if (nd->nd_repstat) {
4179 error = nd->nd_repstat;
4182 NFSM_DISSECT(tl, u_int32_t *,
4183 NFSX_STATFS(nd->nd_flag & ND_NFSV3));
4185 if (NFSHASNFSV3(nmp)) {
4186 sbp->sf_tbytes = fxdr_hyper(tl); tl += 2;
4187 sbp->sf_fbytes = fxdr_hyper(tl); tl += 2;
4188 sbp->sf_abytes = fxdr_hyper(tl); tl += 2;
4189 sbp->sf_tfiles = fxdr_hyper(tl); tl += 2;
4190 sbp->sf_ffiles = fxdr_hyper(tl); tl += 2;
4191 sbp->sf_afiles = fxdr_hyper(tl); tl += 2;
4192 sbp->sf_invarsec = fxdr_unsigned(u_int32_t, *tl);
4193 } else if (NFSHASNFSV4(nmp) == 0) {
4194 sbp->sf_tsize = fxdr_unsigned(u_int32_t, *tl++);
4195 sbp->sf_bsize = fxdr_unsigned(u_int32_t, *tl++);
4196 sbp->sf_blocks = fxdr_unsigned(u_int32_t, *tl++);
4197 sbp->sf_bfree = fxdr_unsigned(u_int32_t, *tl++);
4198 sbp->sf_bavail = fxdr_unsigned(u_int32_t, *tl);
4201 mbuf_freem(nd->nd_mrep);
4209 nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc,
4210 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
4213 struct nfsrv_descript nfsd, *nd = &nfsd;
4214 struct nfsmount *nmp;
4216 nfsattrbit_t attrbits;
4220 nmp = VFSTONFS(vnode_mount(vp));
4221 if (NFSHASNFSV4(nmp)) {
4223 * For V4, you actually do a getattr.
4225 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
4226 NFSPATHCONF_GETATTRBIT(&attrbits);
4227 (void) nfsrv_putattrbit(nd, &attrbits);
4228 nd->nd_flag |= ND_USEGSSNAME;
4229 error = nfscl_request(nd, vp, p, cred, stuff);
4232 if (nd->nd_repstat == 0) {
4233 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
4234 pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, p,
4239 error = nd->nd_repstat;
4242 NFSCL_REQSTART(nd, NFSPROC_PATHCONF, vp);
4243 error = nfscl_request(nd, vp, p, cred, stuff);
4246 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
4247 if (nd->nd_repstat && !error)
4248 error = nd->nd_repstat;
4250 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3PATHCONF);
4251 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl++);
4252 pc->pc_namemax = fxdr_unsigned(u_int32_t, *tl++);
4253 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl++);
4254 pc->pc_chownrestricted =
4255 fxdr_unsigned(u_int32_t, *tl++);
4256 pc->pc_caseinsensitive =
4257 fxdr_unsigned(u_int32_t, *tl++);
4258 pc->pc_casepreserving = fxdr_unsigned(u_int32_t, *tl);
4262 mbuf_freem(nd->nd_mrep);
4267 * nfs version 3 fsinfo rpc call
4270 nfsrpc_fsinfo(vnode_t vp, struct nfsfsinfo *fsp, struct ucred *cred,
4271 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
4274 struct nfsrv_descript nfsd, *nd = &nfsd;
4278 NFSCL_REQSTART(nd, NFSPROC_FSINFO, vp);
4279 error = nfscl_request(nd, vp, p, cred, stuff);
4282 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
4283 if (nd->nd_repstat && !error)
4284 error = nd->nd_repstat;
4286 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3FSINFO);
4287 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *tl++);
4288 fsp->fs_rtpref = fxdr_unsigned(u_int32_t, *tl++);
4289 fsp->fs_rtmult = fxdr_unsigned(u_int32_t, *tl++);
4290 fsp->fs_wtmax = fxdr_unsigned(u_int32_t, *tl++);
4291 fsp->fs_wtpref = fxdr_unsigned(u_int32_t, *tl++);
4292 fsp->fs_wtmult = fxdr_unsigned(u_int32_t, *tl++);
4293 fsp->fs_dtpref = fxdr_unsigned(u_int32_t, *tl++);
4294 fsp->fs_maxfilesize = fxdr_hyper(tl);
4296 fxdr_nfsv3time(tl, &fsp->fs_timedelta);
4298 fsp->fs_properties = fxdr_unsigned(u_int32_t, *tl);
4301 mbuf_freem(nd->nd_mrep);
4306 * This function performs the Renew RPC.
4309 nfsrpc_renew(struct nfsclclient *clp, struct nfsclds *dsp, struct ucred *cred,
4313 struct nfsrv_descript nfsd;
4314 struct nfsrv_descript *nd = &nfsd;
4315 struct nfsmount *nmp;
4317 struct nfssockreq *nrp;
4318 struct nfsclsession *tsep;
4320 nmp = clp->nfsc_nmp;
4324 nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL, NULL);
4326 nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL,
4327 &dsp->nfsclds_sess);
4328 if (!NFSHASNFSV4N(nmp)) {
4329 /* NFSv4.1 just uses a Sequence Op and not a Renew. */
4330 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4331 tsep = nfsmnt_mdssession(nmp);
4332 *tl++ = tsep->nfsess_clientid.lval[0];
4333 *tl = tsep->nfsess_clientid.lval[1];
4337 nrp = dsp->nfsclds_sockp;
4339 /* If NULL, use the MDS socket. */
4340 nrp = &nmp->nm_sockreq;
4341 nd->nd_flag |= ND_USEGSSNAME;
4343 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
4344 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4346 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
4347 NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
4350 error = nd->nd_repstat;
4351 mbuf_freem(nd->nd_mrep);
4356 * This function performs the Releaselockowner RPC.
4359 nfsrpc_rellockown(struct nfsmount *nmp, struct nfscllockowner *lp,
4360 uint8_t *fh, int fhlen, struct ucred *cred, NFSPROC_T *p)
4362 struct nfsrv_descript nfsd, *nd = &nfsd;
4365 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
4366 struct nfsclsession *tsep;
4368 if (NFSHASNFSV4N(nmp)) {
4369 /* For NFSv4.1, do a FreeStateID. */
4370 nfscl_reqstart(nd, NFSPROC_FREESTATEID, nmp, NULL, 0, NULL,
4372 nfsm_stateidtom(nd, &lp->nfsl_stateid, NFSSTATEID_PUTSTATEID);
4374 nfscl_reqstart(nd, NFSPROC_RELEASELCKOWN, nmp, NULL, 0, NULL,
4376 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4377 tsep = nfsmnt_mdssession(nmp);
4378 *tl++ = tsep->nfsess_clientid.lval[0];
4379 *tl = tsep->nfsess_clientid.lval[1];
4380 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN);
4381 NFSBCOPY(fh, &own[NFSV4CL_LOCKNAMELEN], fhlen);
4382 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen);
4384 nd->nd_flag |= ND_USEGSSNAME;
4385 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4386 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4389 error = nd->nd_repstat;
4390 mbuf_freem(nd->nd_mrep);
4395 * This function performs the Compound to get the mount pt FH.
4398 nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred,
4402 struct nfsrv_descript nfsd;
4403 struct nfsrv_descript *nd = &nfsd;
4405 int error, cnt, len, setnil;
4408 nfscl_reqstart(nd, NFSPROC_PUTROOTFH, nmp, NULL, 0, &opcntp, NULL);
4416 while (*cp2 != '\0' && *cp2 != '/')
4423 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4424 *tl = txdr_unsigned(NFSV4OP_LOOKUP);
4425 nfsm_strtom(nd, cp, strlen(cp));
4431 } while (*cp != '\0');
4432 if (NFSHASNFSV4N(nmp))
4433 /* Has a Sequence Op done by nfscl_reqstart(). */
4434 *opcntp = txdr_unsigned(3 + cnt);
4436 *opcntp = txdr_unsigned(2 + cnt);
4437 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4438 *tl = txdr_unsigned(NFSV4OP_GETFH);
4439 nd->nd_flag |= ND_USEGSSNAME;
4440 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4441 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4444 if (nd->nd_repstat == 0) {
4445 NFSM_DISSECT(tl, u_int32_t *, (3 + 2 * cnt) * NFSX_UNSIGNED);
4446 tl += (2 + 2 * cnt);
4447 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
4449 nd->nd_repstat = NFSERR_BADXDR;
4451 nd->nd_repstat = nfsrv_mtostr(nd, nmp->nm_fh, len);
4452 if (nd->nd_repstat == 0)
4453 nmp->nm_fhsize = len;
4456 error = nd->nd_repstat;
4458 mbuf_freem(nd->nd_mrep);
4463 * This function performs the Delegreturn RPC.
4466 nfsrpc_delegreturn(struct nfscldeleg *dp, struct ucred *cred,
4467 struct nfsmount *nmp, NFSPROC_T *p, int syscred)
4470 struct nfsrv_descript nfsd;
4471 struct nfsrv_descript *nd = &nfsd;
4474 nfscl_reqstart(nd, NFSPROC_DELEGRETURN, nmp, dp->nfsdl_fh,
4475 dp->nfsdl_fhlen, NULL, NULL);
4476 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
4477 if (NFSHASNFSV4N(nmp))
4480 *tl++ = dp->nfsdl_stateid.seqid;
4481 *tl++ = dp->nfsdl_stateid.other[0];
4482 *tl++ = dp->nfsdl_stateid.other[1];
4483 *tl = dp->nfsdl_stateid.other[2];
4485 nd->nd_flag |= ND_USEGSSNAME;
4486 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4487 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4490 error = nd->nd_repstat;
4491 mbuf_freem(nd->nd_mrep);
4499 nfsrpc_getacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
4500 struct acl *aclp, void *stuff)
4502 struct nfsrv_descript nfsd, *nd = &nfsd;
4504 nfsattrbit_t attrbits;
4505 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
4507 if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp))
4508 return (EOPNOTSUPP);
4509 NFSCL_REQSTART(nd, NFSPROC_GETACL, vp);
4510 NFSZERO_ATTRBIT(&attrbits);
4511 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
4512 (void) nfsrv_putattrbit(nd, &attrbits);
4513 error = nfscl_request(nd, vp, p, cred, stuff);
4516 if (!nd->nd_repstat)
4517 error = nfsv4_loadattr(nd, vp, NULL, NULL, NULL, 0, NULL,
4518 NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, p, cred);
4520 error = nd->nd_repstat;
4521 mbuf_freem(nd->nd_mrep);
4529 nfsrpc_setacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
4530 struct acl *aclp, void *stuff)
4533 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
4535 if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp))
4536 return (EOPNOTSUPP);
4537 error = nfsrpc_setattr(vp, NULL, aclp, cred, p, NULL, NULL, stuff);
4545 nfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
4546 struct acl *aclp, nfsv4stateid_t *stateidp, void *stuff)
4548 struct nfsrv_descript nfsd, *nd = &nfsd;
4550 nfsattrbit_t attrbits;
4551 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
4553 if (!NFSHASNFSV4(nmp))
4554 return (EOPNOTSUPP);
4555 NFSCL_REQSTART(nd, NFSPROC_SETACL, vp);
4556 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
4557 NFSZERO_ATTRBIT(&attrbits);
4558 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
4559 (void) nfsv4_fillattr(nd, vnode_mount(vp), vp, aclp, NULL, NULL, 0,
4560 &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0);
4561 error = nfscl_request(nd, vp, p, cred, stuff);
4564 /* Don't care about the pre/postop attributes */
4565 mbuf_freem(nd->nd_mrep);
4566 return (nd->nd_repstat);
4570 * Do the NFSv4.1 Exchange ID.
4573 nfsrpc_exchangeid(struct nfsmount *nmp, struct nfsclclient *clp,
4574 struct nfssockreq *nrp, uint32_t exchflags, struct nfsclds **dspp,
4575 struct ucred *cred, NFSPROC_T *p)
4577 uint32_t *tl, v41flags;
4578 struct nfsrv_descript nfsd;
4579 struct nfsrv_descript *nd = &nfsd;
4580 struct nfsclds *dsp;
4581 struct timespec verstime;
4585 nfscl_reqstart(nd, NFSPROC_EXCHANGEID, nmp, NULL, 0, NULL, NULL);
4586 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4587 *tl++ = txdr_unsigned(nfsboottime.tv_sec); /* Client owner */
4588 *tl = txdr_unsigned(clp->nfsc_rev);
4589 (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen);
4591 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
4592 *tl++ = txdr_unsigned(exchflags);
4593 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE);
4595 /* Set the implementation id4 */
4596 *tl = txdr_unsigned(1);
4597 (void) nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
4598 (void) nfsm_strtom(nd, version, strlen(version));
4599 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
4600 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */
4601 verstime.tv_nsec = 0;
4602 txdr_nfsv4time(&verstime, tl);
4603 nd->nd_flag |= ND_USEGSSNAME;
4604 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
4605 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4606 NFSCL_DEBUG(1, "exchangeid err=%d reps=%d\n", error,
4607 (int)nd->nd_repstat);
4610 if (nd->nd_repstat == 0) {
4611 NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_UNSIGNED + NFSX_HYPER);
4612 len = fxdr_unsigned(int, *(tl + 7));
4613 if (len < 0 || len > NFSV4_OPAQUELIMIT) {
4614 error = NFSERR_BADXDR;
4617 dsp = malloc(sizeof(struct nfsclds) + len + 1, M_NFSCLDS,
4619 dsp->nfsclds_expire = NFSD_MONOSEC + clp->nfsc_renew;
4620 dsp->nfsclds_servownlen = len;
4621 dsp->nfsclds_sess.nfsess_clientid.lval[0] = *tl++;
4622 dsp->nfsclds_sess.nfsess_clientid.lval[1] = *tl++;
4623 dsp->nfsclds_sess.nfsess_sequenceid =
4624 fxdr_unsigned(uint32_t, *tl++);
4625 v41flags = fxdr_unsigned(uint32_t, *tl);
4626 if ((v41flags & NFSV4EXCH_USEPNFSMDS) != 0 &&
4627 NFSHASPNFSOPT(nmp)) {
4628 NFSCL_DEBUG(1, "set PNFS\n");
4630 nmp->nm_state |= NFSSTA_PNFS;
4632 dsp->nfsclds_flags |= NFSCLDS_MDS;
4634 if ((v41flags & NFSV4EXCH_USEPNFSDS) != 0)
4635 dsp->nfsclds_flags |= NFSCLDS_DS;
4637 nd->nd_repstat = nfsrv_mtostr(nd,
4638 dsp->nfsclds_serverown, len);
4639 if (nd->nd_repstat == 0) {
4640 mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF);
4641 mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession",
4643 nfscl_initsessionslots(&dsp->nfsclds_sess);
4646 free(dsp, M_NFSCLDS);
4648 error = nd->nd_repstat;
4650 mbuf_freem(nd->nd_mrep);
4655 * Do the NFSv4.1 Create Session.
4658 nfsrpc_createsession(struct nfsmount *nmp, struct nfsclsession *sep,
4659 struct nfssockreq *nrp, uint32_t sequenceid, int mds, struct ucred *cred,
4662 uint32_t crflags, maxval, *tl;
4663 struct nfsrv_descript nfsd;
4664 struct nfsrv_descript *nd = &nfsd;
4667 /* Make sure nm_rsize, nm_wsize is set. */
4668 if (nmp->nm_rsize > NFS_MAXBSIZE || nmp->nm_rsize == 0)
4669 nmp->nm_rsize = NFS_MAXBSIZE;
4670 if (nmp->nm_wsize > NFS_MAXBSIZE || nmp->nm_wsize == 0)
4671 nmp->nm_wsize = NFS_MAXBSIZE;
4672 nfscl_reqstart(nd, NFSPROC_CREATESESSION, nmp, NULL, 0, NULL, NULL);
4673 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4674 *tl++ = sep->nfsess_clientid.lval[0];
4675 *tl++ = sep->nfsess_clientid.lval[1];
4676 *tl++ = txdr_unsigned(sequenceid);
4677 crflags = (NFSMNT_RDONLY(nmp->nm_mountp) ? 0 : NFSV4CRSESS_PERSIST);
4678 if (nfscl_enablecallb != 0 && nfs_numnfscbd > 0 && mds != 0)
4679 crflags |= NFSV4CRSESS_CONNBACKCHAN;
4680 *tl = txdr_unsigned(crflags);
4682 /* Fill in fore channel attributes. */
4683 NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4684 *tl++ = 0; /* Header pad size */
4685 *tl++ = txdr_unsigned(nmp->nm_wsize + NFS_MAXXDR);/* Max request size */
4686 *tl++ = txdr_unsigned(nmp->nm_rsize + NFS_MAXXDR);/* Max reply size */
4687 *tl++ = txdr_unsigned(4096); /* Max response size cached */
4688 *tl++ = txdr_unsigned(20); /* Max operations */
4689 *tl++ = txdr_unsigned(64); /* Max slots */
4690 *tl = 0; /* No rdma ird */
4692 /* Fill in back channel attributes. */
4693 NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4694 *tl++ = 0; /* Header pad size */
4695 *tl++ = txdr_unsigned(10000); /* Max request size */
4696 *tl++ = txdr_unsigned(10000); /* Max response size */
4697 *tl++ = txdr_unsigned(4096); /* Max response size cached */
4698 *tl++ = txdr_unsigned(4); /* Max operations */
4699 *tl++ = txdr_unsigned(NFSV4_CBSLOTS); /* Max slots */
4700 *tl = 0; /* No rdma ird */
4702 NFSM_BUILD(tl, uint32_t *, 8 * NFSX_UNSIGNED);
4703 *tl++ = txdr_unsigned(NFS_CALLBCKPROG); /* Call back prog # */
4705 /* Allow AUTH_SYS callbacks as uid, gid == 0. */
4706 *tl++ = txdr_unsigned(1); /* Auth_sys only */
4707 *tl++ = txdr_unsigned(AUTH_SYS); /* AUTH_SYS type */
4708 *tl++ = txdr_unsigned(nfsboottime.tv_sec); /* time stamp */
4709 *tl++ = 0; /* Null machine name */
4710 *tl++ = 0; /* Uid == 0 */
4711 *tl++ = 0; /* Gid == 0 */
4712 *tl = 0; /* No additional gids */
4713 nd->nd_flag |= ND_USEGSSNAME;
4714 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, NFS_PROG,
4715 NFS_VER4, NULL, 1, NULL, NULL);
4718 if (nd->nd_repstat == 0) {
4719 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID +
4721 bcopy(tl, sep->nfsess_sessionid, NFSX_V4SESSIONID);
4722 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4723 sep->nfsess_sequenceid = fxdr_unsigned(uint32_t, *tl++);
4724 crflags = fxdr_unsigned(uint32_t, *tl);
4725 if ((crflags & NFSV4CRSESS_PERSIST) != 0 && mds != 0) {
4727 nmp->nm_state |= NFSSTA_SESSPERSIST;
4731 /* Get the fore channel slot count. */
4732 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4733 tl++; /* Skip the header pad size. */
4735 /* Make sure nm_wsize is small enough. */
4736 maxval = fxdr_unsigned(uint32_t, *tl++);
4737 while (maxval < nmp->nm_wsize + NFS_MAXXDR) {
4738 if (nmp->nm_wsize > 8096)
4744 /* Make sure nm_rsize is small enough. */
4745 maxval = fxdr_unsigned(uint32_t, *tl++);
4746 while (maxval < nmp->nm_rsize + NFS_MAXXDR) {
4747 if (nmp->nm_rsize > 8096)
4753 sep->nfsess_maxcache = fxdr_unsigned(int, *tl++);
4755 sep->nfsess_foreslots = fxdr_unsigned(uint16_t, *tl++);
4756 NFSCL_DEBUG(4, "fore slots=%d\n", (int)sep->nfsess_foreslots);
4757 irdcnt = fxdr_unsigned(int, *tl);
4759 NFSM_DISSECT(tl, uint32_t *, irdcnt * NFSX_UNSIGNED);
4761 /* and the back channel slot count. */
4762 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4764 sep->nfsess_backslots = fxdr_unsigned(uint16_t, *tl);
4765 NFSCL_DEBUG(4, "back slots=%d\n", (int)sep->nfsess_backslots);
4767 error = nd->nd_repstat;
4769 mbuf_freem(nd->nd_mrep);
4774 * Do the NFSv4.1 Destroy Session.
4777 nfsrpc_destroysession(struct nfsmount *nmp, struct nfsclclient *clp,
4778 struct ucred *cred, NFSPROC_T *p)
4781 struct nfsrv_descript nfsd;
4782 struct nfsrv_descript *nd = &nfsd;
4784 struct nfsclsession *tsep;
4786 nfscl_reqstart(nd, NFSPROC_DESTROYSESSION, nmp, NULL, 0, NULL, NULL);
4787 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4788 tsep = nfsmnt_mdssession(nmp);
4789 bcopy(tsep->nfsess_sessionid, tl, NFSX_V4SESSIONID);
4790 nd->nd_flag |= ND_USEGSSNAME;
4791 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4792 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4795 error = nd->nd_repstat;
4796 mbuf_freem(nd->nd_mrep);
4801 * Do the NFSv4.1 Destroy Client.
4804 nfsrpc_destroyclient(struct nfsmount *nmp, struct nfsclclient *clp,
4805 struct ucred *cred, NFSPROC_T *p)
4808 struct nfsrv_descript nfsd;
4809 struct nfsrv_descript *nd = &nfsd;
4811 struct nfsclsession *tsep;
4813 nfscl_reqstart(nd, NFSPROC_DESTROYCLIENT, nmp, NULL, 0, NULL, NULL);
4814 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4815 tsep = nfsmnt_mdssession(nmp);
4816 *tl++ = tsep->nfsess_clientid.lval[0];
4817 *tl = tsep->nfsess_clientid.lval[1];
4818 nd->nd_flag |= ND_USEGSSNAME;
4819 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4820 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4823 error = nd->nd_repstat;
4824 mbuf_freem(nd->nd_mrep);
4829 * Do the NFSv4.1 LayoutGet.
4832 nfsrpc_layoutget(struct nfsmount *nmp, uint8_t *fhp, int fhlen, int iomode,
4833 uint64_t offset, uint64_t len, uint64_t minlen, int layoutlen,
4834 nfsv4stateid_t *stateidp, int *retonclosep, struct nfsclflayouthead *flhp,
4835 struct ucred *cred, NFSPROC_T *p, void *stuff)
4837 struct nfsrv_descript nfsd, *nd = &nfsd;
4840 nfscl_reqstart(nd, NFSPROC_LAYOUTGET, nmp, fhp, fhlen, NULL, NULL);
4841 nfsrv_setuplayoutget(nd, iomode, offset, len, minlen, stateidp,
4843 nd->nd_flag |= ND_USEGSSNAME;
4844 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4845 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4846 NFSCL_DEBUG(4, "layget err=%d st=%d\n", error, nd->nd_repstat);
4849 if (nd->nd_repstat == 0)
4850 error = nfsrv_parselayoutget(nd, stateidp, retonclosep, flhp);
4851 if (error == 0 && nd->nd_repstat != 0)
4852 error = nd->nd_repstat;
4853 mbuf_freem(nd->nd_mrep);
4858 * Do the NFSv4.1 Get Device Info.
4861 nfsrpc_getdeviceinfo(struct nfsmount *nmp, uint8_t *deviceid, int layouttype,
4862 uint32_t *notifybitsp, struct nfscldevinfo **ndip, struct ucred *cred,
4866 struct nfsrv_descript nfsd;
4867 struct nfsrv_descript *nd = &nfsd;
4868 struct sockaddr_storage ss;
4869 struct nfsclds *dsp = NULL, **dspp;
4870 struct nfscldevinfo *ndi;
4871 int addrcnt, bitcnt, error, i, isudp, j, pos, safilled, stripecnt;
4872 uint8_t stripeindex;
4876 nfscl_reqstart(nd, NFSPROC_GETDEVICEINFO, nmp, NULL, 0, NULL, NULL);
4877 NFSM_BUILD(tl, uint32_t *, NFSX_V4DEVICEID + 3 * NFSX_UNSIGNED);
4878 NFSBCOPY(deviceid, tl, NFSX_V4DEVICEID);
4879 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
4880 *tl++ = txdr_unsigned(layouttype);
4881 *tl++ = txdr_unsigned(100000);
4882 if (notifybitsp != NULL && *notifybitsp != 0) {
4883 *tl = txdr_unsigned(1); /* One word of bits. */
4884 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4885 *tl = txdr_unsigned(*notifybitsp);
4887 *tl = txdr_unsigned(0);
4888 nd->nd_flag |= ND_USEGSSNAME;
4889 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4890 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4893 if (nd->nd_repstat == 0) {
4894 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED);
4895 if (layouttype != fxdr_unsigned(int, *tl++))
4896 printf("EEK! devinfo layout type not same!\n");
4897 stripecnt = fxdr_unsigned(int, *++tl);
4898 NFSCL_DEBUG(4, "stripecnt=%d\n", stripecnt);
4899 if (stripecnt < 1 || stripecnt > 4096) {
4900 printf("NFS devinfo stripecnt %d: out of range\n",
4902 error = NFSERR_BADXDR;
4905 NFSM_DISSECT(tl, uint32_t *, (stripecnt + 1) * NFSX_UNSIGNED);
4906 addrcnt = fxdr_unsigned(int, *(tl + stripecnt));
4907 NFSCL_DEBUG(4, "addrcnt=%d\n", addrcnt);
4908 if (addrcnt < 1 || addrcnt > 128) {
4909 printf("NFS devinfo addrcnt %d: out of range\n",
4911 error = NFSERR_BADXDR;
4916 * Now we know how many stripe indices and addresses, so
4917 * we can allocate the structure the correct size.
4919 i = (stripecnt * sizeof(uint8_t)) / sizeof(struct nfsclds *)
4921 NFSCL_DEBUG(4, "stripeindices=%d\n", i);
4922 ndi = malloc(sizeof(*ndi) + (addrcnt + i) *
4923 sizeof(struct nfsclds *), M_NFSDEVINFO, M_WAITOK | M_ZERO);
4924 NFSBCOPY(deviceid, ndi->nfsdi_deviceid, NFSX_V4DEVICEID);
4925 ndi->nfsdi_refcnt = 0;
4926 ndi->nfsdi_stripecnt = stripecnt;
4927 ndi->nfsdi_addrcnt = addrcnt;
4928 /* Fill in the stripe indices. */
4929 for (i = 0; i < stripecnt; i++) {
4930 stripeindex = fxdr_unsigned(uint8_t, *tl++);
4931 NFSCL_DEBUG(4, "stripeind=%d\n", stripeindex);
4932 if (stripeindex >= addrcnt) {
4933 printf("NFS devinfo stripeindex %d: too big\n",
4935 error = NFSERR_BADXDR;
4938 nfsfldi_setstripeindex(ndi, i, stripeindex);
4941 /* Now, dissect the server address(es). */
4943 for (i = 0; i < addrcnt; i++) {
4944 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4945 cnt = fxdr_unsigned(uint32_t, *tl);
4947 printf("NFS devinfo 0 len addrlist\n");
4948 error = NFSERR_BADXDR;
4951 dspp = nfsfldi_addr(ndi, i);
4952 pos = arc4random() % cnt; /* Choose one. */
4954 for (j = 0; j < cnt; j++) {
4955 error = nfsv4_getipaddr(nd, &ss, &isudp);
4956 if (error != 0 && error != EPERM) {
4957 error = NFSERR_BADXDR;
4960 if (error == 0 && isudp == 0) {
4963 * - use "pos" entry if it is of the
4964 * same af_family or none of them
4965 * is of the same af_family
4967 * - use the first one of the same
4970 if ((safilled == 0 && ss.ss_family ==
4971 nmp->nm_nam->sa_family) ||
4973 (safilled == 0 || ss.ss_family ==
4974 nmp->nm_nam->sa_family)) ||
4975 (safilled == 1 && ss.ss_family ==
4976 nmp->nm_nam->sa_family)) {
4977 error = nfsrpc_fillsa(nmp, &ss,
4982 nmp->nm_nam->sa_family)
4994 /* And the notify bits. */
4995 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4996 if (safilled != 0) {
4997 bitcnt = fxdr_unsigned(int, *tl);
4999 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5000 if (notifybitsp != NULL)
5002 fxdr_unsigned(uint32_t, *tl);
5008 if (nd->nd_repstat != 0)
5009 error = nd->nd_repstat;
5011 if (error != 0 && ndi != NULL)
5012 nfscl_freedevinfo(ndi);
5013 mbuf_freem(nd->nd_mrep);
5018 * Do the NFSv4.1 LayoutCommit.
5021 nfsrpc_layoutcommit(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim,
5022 uint64_t off, uint64_t len, uint64_t lastbyte, nfsv4stateid_t *stateidp,
5023 int layouttype, int layoutupdatecnt, uint8_t *layp, struct ucred *cred,
5024 NFSPROC_T *p, void *stuff)
5027 struct nfsrv_descript nfsd, *nd = &nfsd;
5028 int error, outcnt, i;
5031 nfscl_reqstart(nd, NFSPROC_LAYOUTCOMMIT, nmp, fh, fhlen, NULL, NULL);
5032 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
5034 txdr_hyper(off, tl);
5036 txdr_hyper(len, tl);
5039 *tl++ = newnfs_true;
5041 *tl++ = newnfs_false;
5042 *tl++ = txdr_unsigned(stateidp->seqid);
5043 *tl++ = stateidp->other[0];
5044 *tl++ = stateidp->other[1];
5045 *tl++ = stateidp->other[2];
5046 *tl++ = newnfs_true;
5049 else if (lastbyte >= (off + len))
5050 lastbyte = off + len - 1;
5051 txdr_hyper(lastbyte, tl);
5053 *tl++ = newnfs_false;
5054 *tl++ = txdr_unsigned(layouttype);
5055 *tl = txdr_unsigned(layoutupdatecnt);
5056 if (layoutupdatecnt > 0) {
5057 KASSERT(layouttype != NFSLAYOUT_NFSV4_1_FILES,
5058 ("Must be nil for Files Layout"));
5059 outcnt = NFSM_RNDUP(layoutupdatecnt);
5060 NFSM_BUILD(cp, uint8_t *, outcnt);
5061 NFSBCOPY(layp, cp, layoutupdatecnt);
5062 cp += layoutupdatecnt;
5063 for (i = 0; i < (outcnt - layoutupdatecnt); i++)
5066 nd->nd_flag |= ND_USEGSSNAME;
5067 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5068 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5071 error = nd->nd_repstat;
5072 mbuf_freem(nd->nd_mrep);
5077 * Do the NFSv4.1 LayoutReturn.
5080 nfsrpc_layoutreturn(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim,
5081 int layouttype, uint32_t iomode, int layoutreturn, uint64_t offset,
5082 uint64_t len, nfsv4stateid_t *stateidp, int layoutcnt, uint32_t *layp,
5083 struct ucred *cred, NFSPROC_T *p, void *stuff)
5086 struct nfsrv_descript nfsd, *nd = &nfsd;
5087 int error, outcnt, i;
5090 nfscl_reqstart(nd, NFSPROC_LAYOUTRETURN, nmp, fh, fhlen, NULL, NULL);
5091 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED);
5093 *tl++ = newnfs_true;
5095 *tl++ = newnfs_false;
5096 *tl++ = txdr_unsigned(layouttype);
5097 *tl++ = txdr_unsigned(iomode);
5098 *tl = txdr_unsigned(layoutreturn);
5099 if (layoutreturn == NFSLAYOUTRETURN_FILE) {
5100 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
5102 txdr_hyper(offset, tl);
5104 txdr_hyper(len, tl);
5106 NFSCL_DEBUG(4, "layoutret stseq=%d\n", (int)stateidp->seqid);
5107 *tl++ = txdr_unsigned(stateidp->seqid);
5108 *tl++ = stateidp->other[0];
5109 *tl++ = stateidp->other[1];
5110 *tl++ = stateidp->other[2];
5111 *tl = txdr_unsigned(layoutcnt);
5112 if (layoutcnt > 0) {
5113 outcnt = NFSM_RNDUP(layoutcnt);
5114 NFSM_BUILD(cp, uint8_t *, outcnt);
5115 NFSBCOPY(layp, cp, layoutcnt);
5117 for (i = 0; i < (outcnt - layoutcnt); i++)
5121 nd->nd_flag |= ND_USEGSSNAME;
5122 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5123 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5126 if (nd->nd_repstat == 0) {
5127 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5129 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
5130 stateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
5131 stateidp->other[0] = *tl++;
5132 stateidp->other[1] = *tl++;
5133 stateidp->other[2] = *tl;
5136 error = nd->nd_repstat;
5138 mbuf_freem(nd->nd_mrep);
5143 * Acquire a layout and devinfo, if possible. The caller must have acquired
5144 * a reference count on the nfsclclient structure before calling this.
5145 * Return the layout in lypp with a reference count on it, if successful.
5148 nfsrpc_getlayout(struct nfsmount *nmp, vnode_t vp, struct nfsfh *nfhp,
5149 int iomode, uint32_t *notifybitsp, nfsv4stateid_t *stateidp, uint64_t off,
5150 struct nfscllayout **lypp, struct ucred *cred, NFSPROC_T *p)
5152 struct nfscllayout *lyp;
5153 struct nfsclflayout *flp;
5154 struct nfsclflayouthead flh;
5155 int error = 0, islocked, layoutlen, recalled, retonclose;
5156 nfsv4stateid_t stateid;
5157 struct nfsclsession *tsep;
5161 * If lyp is returned non-NULL, there will be a refcnt (shared lock)
5162 * on it, iff flp != NULL or a lock (exclusive lock) on it iff
5165 lyp = nfscl_getlayout(nmp->nm_clp, nfhp->nfh_fh, nfhp->nfh_len,
5166 off, &flp, &recalled);
5168 if (lyp == NULL || flp == NULL) {
5172 tsep = nfsmnt_mdssession(nmp);
5173 layoutlen = tsep->nfsess_maxcache -
5174 (NFSX_STATEID + 3 * NFSX_UNSIGNED);
5177 stateid.other[0] = stateidp->other[0];
5178 stateid.other[1] = stateidp->other[1];
5179 stateid.other[2] = stateidp->other[2];
5180 error = nfsrpc_layoutget(nmp, nfhp->nfh_fh,
5181 nfhp->nfh_len, iomode, (uint64_t)0, UINT64_MAX,
5182 (uint64_t)0, layoutlen, &stateid, &retonclose,
5183 &flh, cred, p, NULL);
5186 stateid.seqid = lyp->nfsly_stateid.seqid;
5187 stateid.other[0] = lyp->nfsly_stateid.other[0];
5188 stateid.other[1] = lyp->nfsly_stateid.other[1];
5189 stateid.other[2] = lyp->nfsly_stateid.other[2];
5190 error = nfsrpc_layoutget(nmp, nfhp->nfh_fh,
5191 nfhp->nfh_len, iomode, off, UINT64_MAX,
5192 (uint64_t)0, layoutlen, &stateid, &retonclose,
5193 &flh, cred, p, NULL);
5195 error = nfsrpc_layoutgetres(nmp, vp, nfhp->nfh_fh,
5196 nfhp->nfh_len, &stateid, retonclose, notifybitsp, &lyp,
5197 &flh, error, NULL, cred, p);
5200 else if (islocked != 0)
5201 nfscl_rellayout(lyp, 1);
5208 * Do a TCP connection plus exchange id and create session.
5209 * If successful, a "struct nfsclds" is linked into the list for the
5210 * mount point and a pointer to it is returned.
5213 nfsrpc_fillsa(struct nfsmount *nmp, struct sockaddr_storage *ssp,
5214 struct nfsclds **dspp, NFSPROC_T *p)
5216 struct sockaddr_in *msad, *sad, *ssd;
5217 struct sockaddr_in6 *msad6, *sad6, *ssd6;
5218 struct nfsclclient *clp;
5219 struct nfssockreq *nrp;
5220 struct nfsclds *dsp, *tdsp;
5222 enum nfsclds_state retv;
5223 uint32_t sequenceid;
5225 KASSERT(nmp->nm_sockreq.nr_cred != NULL,
5226 ("nfsrpc_fillsa: NULL nr_cred"));
5232 if (ssp->ss_family == AF_INET) {
5233 ssd = (struct sockaddr_in *)ssp;
5237 * Check to see if we already have a session for this
5238 * address that is usable for a DS.
5239 * Note that the MDS's address is in a different place
5240 * than the sessions already acquired for DS's.
5242 msad = (struct sockaddr_in *)nmp->nm_sockreq.nr_nam;
5243 tdsp = TAILQ_FIRST(&nmp->nm_sess);
5244 while (tdsp != NULL) {
5245 if (msad != NULL && msad->sin_family == AF_INET &&
5246 ssd->sin_addr.s_addr == msad->sin_addr.s_addr &&
5247 ssd->sin_port == msad->sin_port &&
5248 (tdsp->nfsclds_flags & NFSCLDS_DS) != 0 &&
5249 tdsp->nfsclds_sess.nfsess_defunct == 0) {
5252 NFSCL_DEBUG(4, "fnd same addr\n");
5255 tdsp = TAILQ_NEXT(tdsp, nfsclds_list);
5256 if (tdsp != NULL && tdsp->nfsclds_sockp != NULL)
5257 msad = (struct sockaddr_in *)
5258 tdsp->nfsclds_sockp->nr_nam;
5264 /* No IP address match, so look for new/trunked one. */
5265 sad = malloc(sizeof(*sad), M_SONAME, M_WAITOK | M_ZERO);
5266 sad->sin_len = sizeof(*sad);
5267 sad->sin_family = AF_INET;
5268 sad->sin_port = ssd->sin_port;
5269 sad->sin_addr.s_addr = ssd->sin_addr.s_addr;
5270 nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO);
5271 nrp->nr_nam = (struct sockaddr *)sad;
5272 } else if (ssp->ss_family == AF_INET6) {
5273 ssd6 = (struct sockaddr_in6 *)ssp;
5277 * Check to see if we already have a session for this
5278 * address that is usable for a DS.
5279 * Note that the MDS's address is in a different place
5280 * than the sessions already acquired for DS's.
5282 msad6 = (struct sockaddr_in6 *)nmp->nm_sockreq.nr_nam;
5283 tdsp = TAILQ_FIRST(&nmp->nm_sess);
5284 while (tdsp != NULL) {
5285 if (msad6 != NULL && msad6->sin6_family == AF_INET6 &&
5286 IN6_ARE_ADDR_EQUAL(&ssd6->sin6_addr,
5287 &msad6->sin6_addr) &&
5288 ssd6->sin6_port == msad6->sin6_port &&
5289 (tdsp->nfsclds_flags & NFSCLDS_DS) != 0 &&
5290 tdsp->nfsclds_sess.nfsess_defunct == 0) {
5295 tdsp = TAILQ_NEXT(tdsp, nfsclds_list);
5296 if (tdsp != NULL && tdsp->nfsclds_sockp != NULL)
5297 msad6 = (struct sockaddr_in6 *)
5298 tdsp->nfsclds_sockp->nr_nam;
5304 /* No IP address match, so look for new/trunked one. */
5305 sad6 = malloc(sizeof(*sad6), M_SONAME, M_WAITOK | M_ZERO);
5306 sad6->sin6_len = sizeof(*sad6);
5307 sad6->sin6_family = AF_INET6;
5308 sad6->sin6_port = ssd6->sin6_port;
5309 NFSBCOPY(&ssd6->sin6_addr, &sad6->sin6_addr,
5310 sizeof(struct in6_addr));
5311 nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO);
5312 nrp->nr_nam = (struct sockaddr *)sad6;
5316 nrp->nr_sotype = SOCK_STREAM;
5317 mtx_init(&nrp->nr_mtx, "nfssock", NULL, MTX_DEF);
5318 nrp->nr_prog = NFS_PROG;
5319 nrp->nr_vers = NFS_VER4;
5322 * Use the credentials that were used for the mount, which are
5323 * in nmp->nm_sockreq.nr_cred for newnfs_connect() etc.
5324 * Ref. counting the credentials with crhold() is probably not
5325 * necessary, since nm_sockreq.nr_cred won't be crfree()'d until
5326 * unmount, but I did it anyhow.
5328 nrp->nr_cred = crhold(nmp->nm_sockreq.nr_cred);
5329 error = newnfs_connect(nmp, nrp, NULL, p, 0);
5330 NFSCL_DEBUG(3, "DS connect=%d\n", error);
5332 /* Now, do the exchangeid and create session. */
5334 error = nfsrpc_exchangeid(nmp, clp, nrp, NFSV4EXCH_USEPNFSDS,
5335 &dsp, nrp->nr_cred, p);
5336 NFSCL_DEBUG(3, "DS exchangeid=%d\n", error);
5338 newnfs_disconnect(nrp);
5341 dsp->nfsclds_sockp = nrp;
5343 retv = nfscl_getsameserver(nmp, dsp, &tdsp);
5344 NFSCL_DEBUG(3, "getsame ret=%d\n", retv);
5345 if (retv == NFSDSP_USETHISSESSION) {
5348 * If there is already a session for this server,
5351 (void)newnfs_disconnect(nrp);
5352 nfscl_freenfsclds(dsp);
5356 if (retv == NFSDSP_SEQTHISSESSION)
5357 sequenceid = tdsp->nfsclds_sess.nfsess_sequenceid;
5359 sequenceid = dsp->nfsclds_sess.nfsess_sequenceid;
5361 error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess,
5362 nrp, sequenceid, 0, nrp->nr_cred, p);
5363 NFSCL_DEBUG(3, "DS createsess=%d\n", error);
5365 NFSFREECRED(nrp->nr_cred);
5366 NFSFREEMUTEX(&nrp->nr_mtx);
5367 free(nrp->nr_nam, M_SONAME);
5368 free(nrp, M_NFSSOCKREQ);
5371 NFSCL_DEBUG(3, "add DS session\n");
5373 * Put it at the end of the list. That way the list
5374 * is ordered by when the entry was added. This matters
5375 * since the one done first is the one that should be
5376 * used for sequencid'ing any subsequent create sessions.
5379 TAILQ_INSERT_TAIL(&nmp->nm_sess, dsp, nfsclds_list);
5382 } else if (dsp != NULL) {
5383 newnfs_disconnect(nrp);
5384 nfscl_freenfsclds(dsp);
5390 * Do the NFSv4.1 Reclaim Complete.
5393 nfsrpc_reclaimcomplete(struct nfsmount *nmp, struct ucred *cred, NFSPROC_T *p)
5396 struct nfsrv_descript nfsd;
5397 struct nfsrv_descript *nd = &nfsd;
5400 nfscl_reqstart(nd, NFSPROC_RECLAIMCOMPL, nmp, NULL, 0, NULL, NULL);
5401 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5403 nd->nd_flag |= ND_USEGSSNAME;
5404 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5405 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5408 error = nd->nd_repstat;
5409 mbuf_freem(nd->nd_mrep);
5414 * Initialize the slot tables for a session.
5417 nfscl_initsessionslots(struct nfsclsession *sep)
5421 for (i = 0; i < NFSV4_CBSLOTS; i++) {
5422 if (sep->nfsess_cbslots[i].nfssl_reply != NULL)
5423 m_freem(sep->nfsess_cbslots[i].nfssl_reply);
5424 NFSBZERO(&sep->nfsess_cbslots[i], sizeof(struct nfsslot));
5426 for (i = 0; i < 64; i++)
5427 sep->nfsess_slotseq[i] = 0;
5428 sep->nfsess_slots = 0;
5432 * Called to try and do an I/O operation via an NFSv4.1 Data Server (DS).
5435 nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
5436 uint32_t rwaccess, int docommit, struct ucred *cred, NFSPROC_T *p)
5438 struct nfsnode *np = VTONFS(vp);
5439 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
5440 struct nfscllayout *layp;
5441 struct nfscldevinfo *dip;
5442 struct nfsclflayout *rflp;
5443 nfsv4stateid_t stateid;
5444 struct ucred *newcred;
5445 uint64_t lastbyte, len, off, oresid, xfer;
5446 int eof, error, iolaymode, recalled;
5449 if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || nfs_numnfscbd == 0 ||
5450 (np->n_flag & NNOLAYOUT) != 0)
5452 /* Now, get a reference cnt on the clientid for this mount. */
5453 if (nfscl_getref(nmp) == 0)
5456 /* Find an appropriate stateid. */
5457 newcred = NFSNEWCRED(cred);
5458 error = nfscl_getstateid(vp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len,
5459 rwaccess, 1, newcred, p, &stateid, &lckp);
5461 NFSFREECRED(newcred);
5465 /* Search for a layout for this file. */
5466 off = uiop->uio_offset;
5467 layp = nfscl_getlayout(nmp->nm_clp, np->n_fhp->nfh_fh,
5468 np->n_fhp->nfh_len, off, &rflp, &recalled);
5469 if (layp == NULL || rflp == NULL) {
5470 if (recalled != 0) {
5471 NFSFREECRED(newcred);
5476 nfscl_rellayout(layp, (rflp == NULL) ? 1 : 0);
5479 /* Try and get a Layout, if it is supported. */
5480 if (rwaccess == NFSV4OPEN_ACCESSWRITE ||
5481 (np->n_flag & NWRITEOPENED) != 0)
5482 iolaymode = NFSLAYOUTIOMODE_RW;
5484 iolaymode = NFSLAYOUTIOMODE_READ;
5485 error = nfsrpc_getlayout(nmp, vp, np->n_fhp, iolaymode,
5486 NULL, &stateid, off, &layp, newcred, p);
5489 np->n_flag |= NNOLAYOUT;
5492 nfscl_lockderef(lckp);
5493 NFSFREECRED(newcred);
5495 nfscl_rellayout(layp, 0);
5502 * Loop around finding a layout that works for the first part of
5503 * this I/O operation, and then call the function that actually
5507 len = (uint64_t)uiop->uio_resid;
5508 while (len > 0 && error == 0 && eof == 0) {
5509 off = uiop->uio_offset;
5510 error = nfscl_findlayoutforio(layp, off, rwaccess, &rflp);
5512 oresid = xfer = (uint64_t)uiop->uio_resid;
5513 if (xfer > (rflp->nfsfl_end - rflp->nfsfl_off))
5514 xfer = rflp->nfsfl_end - rflp->nfsfl_off;
5515 dip = nfscl_getdevinfo(nmp->nm_clp, rflp->nfsfl_dev,
5518 error = nfscl_doflayoutio(vp, uiop, iomode,
5519 must_commit, &eof, &stateid, rwaccess, dip,
5520 layp, rflp, off, xfer, docommit, newcred,
5522 nfscl_reldevinfo(dip);
5523 lastbyte = off + xfer - 1;
5526 if (lastbyte > layp->nfsly_lastbyte)
5527 layp->nfsly_lastbyte = lastbyte;
5529 } else if (error == NFSERR_OPENMODE &&
5530 rwaccess == NFSV4OPEN_ACCESSREAD) {
5532 nmp->nm_state |= NFSSTA_OPENMODE;
5538 len -= (oresid - (uint64_t)uiop->uio_resid);
5542 nfscl_lockderef(lckp);
5543 NFSFREECRED(newcred);
5544 nfscl_rellayout(layp, 0);
5550 * Find a file layout that will handle the first bytes of the requested
5551 * range and return the information from it needed to to the I/O operation.
5554 nfscl_findlayoutforio(struct nfscllayout *lyp, uint64_t off, uint32_t rwaccess,
5555 struct nfsclflayout **retflpp)
5557 struct nfsclflayout *flp, *nflp, *rflp;
5562 /* For reading, do the Read list first and then the Write list. */
5564 if (rw == NFSV4OPEN_ACCESSREAD)
5565 flp = LIST_FIRST(&lyp->nfsly_flayread);
5567 flp = LIST_FIRST(&lyp->nfsly_flayrw);
5568 while (flp != NULL) {
5569 nflp = LIST_NEXT(flp, nfsfl_list);
5570 if (flp->nfsfl_off > off)
5572 if (flp->nfsfl_end > off &&
5573 (rflp == NULL || rflp->nfsfl_end < flp->nfsfl_end))
5577 if (rw == NFSV4OPEN_ACCESSREAD)
5578 rw = NFSV4OPEN_ACCESSWRITE;
5583 /* This one covers the most bytes starting at off. */
5591 * Do I/O using an NFSv4.1 file layout.
5594 nfscl_doflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
5595 int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp,
5596 struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off,
5597 uint64_t len, int docommit, struct ucred *cred, NFSPROC_T *p)
5599 uint64_t io_off, rel_off, stripe_unit_size, transfer, xfer;
5600 int commit_thru_mds, error, stripe_index, stripe_pos;
5603 struct nfsclds **dspp;
5606 rel_off = off - flp->nfsfl_patoff;
5607 stripe_unit_size = (flp->nfsfl_util >> 6) & 0x3ffffff;
5608 stripe_pos = (rel_off / stripe_unit_size + flp->nfsfl_stripe1) %
5609 dp->nfsdi_stripecnt;
5610 transfer = stripe_unit_size - (rel_off % stripe_unit_size);
5613 /* Loop around, doing I/O for each stripe unit. */
5614 while (len > 0 && error == 0) {
5615 stripe_index = nfsfldi_stripeindex(dp, stripe_pos);
5616 dspp = nfsfldi_addr(dp, stripe_index);
5617 if (len > transfer && docommit == 0)
5621 if ((flp->nfsfl_util & NFSFLAYUTIL_DENSE) != 0) {
5623 if (stripe_pos >= flp->nfsfl_fhcnt)
5625 fhp = flp->nfsfl_fh[stripe_pos];
5626 io_off = (rel_off / (stripe_unit_size *
5627 dp->nfsdi_stripecnt)) * stripe_unit_size +
5628 rel_off % stripe_unit_size;
5630 /* Sparse layout. */
5631 if (flp->nfsfl_fhcnt > 1) {
5632 if (stripe_index >= flp->nfsfl_fhcnt)
5634 fhp = flp->nfsfl_fh[stripe_index];
5635 } else if (flp->nfsfl_fhcnt == 1)
5636 fhp = flp->nfsfl_fh[0];
5641 if ((flp->nfsfl_util & NFSFLAYUTIL_COMMIT_THRU_MDS) != 0) {
5642 commit_thru_mds = 1;
5646 commit_thru_mds = 0;
5647 mtx_lock(&np->n_mtx);
5648 np->n_flag |= NDSCOMMIT;
5649 mtx_unlock(&np->n_mtx);
5651 if (docommit != 0) {
5653 error = nfsrpc_commitds(vp, io_off, xfer,
5654 *dspp, fhp, cred, p);
5657 * Set both eof and uio_resid = 0 to end any
5661 uiop->uio_resid = 0;
5663 mtx_lock(&np->n_mtx);
5664 np->n_flag &= ~NDSCOMMIT;
5665 mtx_unlock(&np->n_mtx);
5667 } else if (rwflag == NFSV4OPEN_ACCESSREAD)
5668 error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp,
5669 io_off, xfer, fhp, cred, p);
5671 error = nfsrpc_writeds(vp, uiop, iomode, must_commit,
5672 stateidp, *dspp, io_off, xfer, fhp, commit_thru_mds,
5676 lyp->nfsly_flags |= NFSLY_WRITTEN;
5681 transfer = stripe_unit_size;
5682 stripe_pos = (stripe_pos + 1) % dp->nfsdi_stripecnt;
5691 * The actual read RPC done to a DS.
5694 nfsrpc_readds(vnode_t vp, struct uio *uiop, nfsv4stateid_t *stateidp, int *eofp,
5695 struct nfsclds *dsp, uint64_t io_off, int len, struct nfsfh *fhp,
5696 struct ucred *cred, NFSPROC_T *p)
5700 struct nfsrv_descript nfsd;
5701 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
5702 struct nfsrv_descript *nd = &nfsd;
5703 struct nfssockreq *nrp;
5706 nfscl_reqstart(nd, NFSPROC_READDS, nmp, fhp->nfh_fh, fhp->nfh_len,
5707 NULL, &dsp->nfsclds_sess);
5708 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO);
5709 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED * 3);
5710 txdr_hyper(io_off, tl);
5711 *(tl + 2) = txdr_unsigned(len);
5712 nrp = dsp->nfsclds_sockp;
5714 /* If NULL, use the MDS socket. */
5715 nrp = &nmp->nm_sockreq;
5716 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
5717 NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
5720 if (nd->nd_repstat != 0) {
5721 error = nd->nd_repstat;
5724 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5725 *eofp = fxdr_unsigned(int, *tl);
5726 NFSM_STRSIZ(retlen, len);
5727 error = nfsm_mbufuio(nd, uiop, retlen);
5729 if (nd->nd_mrep != NULL)
5730 mbuf_freem(nd->nd_mrep);
5735 * The actual write RPC done to a DS.
5738 nfsrpc_writeds(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
5739 nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len,
5740 struct nfsfh *fhp, int commit_thru_mds, struct ucred *cred, NFSPROC_T *p)
5743 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
5744 int error, rlen, commit, committed = NFSWRITE_FILESYNC;
5746 struct nfsrv_descript nfsd;
5747 struct nfsrv_descript *nd = &nfsd;
5748 struct nfssockreq *nrp;
5750 KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1"));
5752 nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh, fhp->nfh_len,
5753 NULL, &dsp->nfsclds_sess);
5754 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO);
5755 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
5756 txdr_hyper(io_off, tl);
5758 *tl++ = txdr_unsigned(*iomode);
5759 *tl = txdr_unsigned(len);
5760 nfsm_uiombuf(nd, uiop, len);
5761 nrp = dsp->nfsclds_sockp;
5763 /* If NULL, use the MDS socket. */
5764 nrp = &nmp->nm_sockreq;
5765 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
5766 NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
5769 if (nd->nd_repstat != 0) {
5771 * In case the rpc gets retried, roll
5772 * the uio fileds changed by nfsm_uiombuf()
5775 uiop->uio_offset -= len;
5776 uio_uio_resid_add(uiop, len);
5777 uio_iov_base_add(uiop, -len);
5778 uio_iov_len_add(uiop, len);
5779 error = nd->nd_repstat;
5781 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF);
5782 rlen = fxdr_unsigned(int, *tl++);
5786 } else if (rlen < len) {
5787 backup = len - rlen;
5788 uio_iov_base_add(uiop, -(backup));
5789 uio_iov_len_add(uiop, backup);
5790 uiop->uio_offset -= backup;
5791 uio_uio_resid_add(uiop, backup);
5794 commit = fxdr_unsigned(int, *tl++);
5797 * Return the lowest commitment level
5798 * obtained by any of the RPCs.
5800 if (committed == NFSWRITE_FILESYNC)
5802 else if (committed == NFSWRITE_DATASYNC &&
5803 commit == NFSWRITE_UNSTABLE)
5805 if (commit_thru_mds != 0) {
5807 if (!NFSHASWRITEVERF(nmp)) {
5808 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
5809 NFSSETWRITEVERF(nmp);
5810 } else if (NFSBCMP(tl, nmp->nm_verf, NFSX_VERF)) {
5812 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
5817 if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) {
5818 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
5819 dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF;
5820 } else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) {
5822 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
5828 if (nd->nd_mrep != NULL)
5829 mbuf_freem(nd->nd_mrep);
5830 *iomode = committed;
5831 if (nd->nd_repstat != 0 && error == 0)
5832 error = nd->nd_repstat;
5837 * Free up the nfsclds structure.
5840 nfscl_freenfsclds(struct nfsclds *dsp)
5846 if (dsp->nfsclds_sockp != NULL) {
5847 NFSFREECRED(dsp->nfsclds_sockp->nr_cred);
5848 NFSFREEMUTEX(&dsp->nfsclds_sockp->nr_mtx);
5849 free(dsp->nfsclds_sockp->nr_nam, M_SONAME);
5850 free(dsp->nfsclds_sockp, M_NFSSOCKREQ);
5852 NFSFREEMUTEX(&dsp->nfsclds_mtx);
5853 NFSFREEMUTEX(&dsp->nfsclds_sess.nfsess_mtx);
5854 for (i = 0; i < NFSV4_CBSLOTS; i++) {
5855 if (dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply != NULL)
5857 dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply);
5859 free(dsp, M_NFSCLDS);
5862 static enum nfsclds_state
5863 nfscl_getsameserver(struct nfsmount *nmp, struct nfsclds *newdsp,
5864 struct nfsclds **retdspp)
5866 struct nfsclds *dsp, *cur_dsp;
5869 * Search the list of nfsclds structures for one with the same
5873 TAILQ_FOREACH(dsp, &nmp->nm_sess, nfsclds_list) {
5874 if (dsp->nfsclds_servownlen == newdsp->nfsclds_servownlen &&
5875 dsp->nfsclds_servownlen != 0 &&
5876 !NFSBCMP(dsp->nfsclds_serverown, newdsp->nfsclds_serverown,
5877 dsp->nfsclds_servownlen) &&
5878 dsp->nfsclds_sess.nfsess_defunct == 0) {
5879 NFSCL_DEBUG(4, "fnd same fdsp=%p dsp=%p flg=0x%x\n",
5880 TAILQ_FIRST(&nmp->nm_sess), dsp,
5881 dsp->nfsclds_flags);
5882 /* Server major id matches. */
5883 if ((dsp->nfsclds_flags & NFSCLDS_DS) != 0) {
5885 return (NFSDSP_USETHISSESSION);
5889 * Note the first match, so it can be used for
5890 * sequence'ing new sessions.
5892 if (cur_dsp == NULL)
5896 if (cur_dsp != NULL) {
5898 return (NFSDSP_SEQTHISSESSION);
5900 return (NFSDSP_NOTFOUND);
5904 * NFS commit rpc to a NFSv4.1 DS.
5907 nfsrpc_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp,
5908 struct nfsfh *fhp, struct ucred *cred, NFSPROC_T *p)
5911 struct nfsrv_descript nfsd, *nd = &nfsd;
5912 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
5913 struct nfssockreq *nrp;
5917 nfscl_reqstart(nd, NFSPROC_COMMITDS, nmp, fhp->nfh_fh, fhp->nfh_len,
5918 NULL, &dsp->nfsclds_sess);
5919 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
5920 txdr_hyper(offset, tl);
5922 *tl = txdr_unsigned(cnt);
5923 nrp = dsp->nfsclds_sockp;
5925 /* If NULL, use the MDS socket. */
5926 nrp = &nmp->nm_sockreq;
5927 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
5928 NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
5931 if (nd->nd_repstat == 0) {
5932 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
5934 if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) {
5935 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
5936 error = NFSERR_STALEWRITEVERF;
5941 if (error == 0 && nd->nd_repstat != 0)
5942 error = nd->nd_repstat;
5943 mbuf_freem(nd->nd_mrep);
5948 * Set up the XDR arguments for the LayoutGet operation.
5951 nfsrv_setuplayoutget(struct nfsrv_descript *nd, int iomode, uint64_t offset,
5952 uint64_t len, uint64_t minlen, nfsv4stateid_t *stateidp, int layoutlen,
5957 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
5959 *tl++ = newnfs_false; /* Don't signal availability. */
5960 *tl++ = txdr_unsigned(NFSLAYOUT_NFSV4_1_FILES);
5961 *tl++ = txdr_unsigned(iomode);
5962 txdr_hyper(offset, tl);
5964 txdr_hyper(len, tl);
5966 txdr_hyper(minlen, tl);
5968 if (usecurstateid != 0) {
5969 /* Special stateid for Current stateid. */
5970 *tl++ = txdr_unsigned(1);
5975 *tl++ = txdr_unsigned(stateidp->seqid);
5976 NFSCL_DEBUG(4, "layget seq=%d\n", (int)stateidp->seqid);
5977 *tl++ = stateidp->other[0];
5978 *tl++ = stateidp->other[1];
5979 *tl++ = stateidp->other[2];
5981 *tl = txdr_unsigned(layoutlen);
5985 * Parse the reply for a successful LayoutGet operation.
5988 nfsrv_parselayoutget(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp,
5989 int *retonclosep, struct nfsclflayouthead *flhp)
5992 struct nfsclflayout *flp, *prevflp, *tflp;
5993 int cnt, error, gotiomode, fhcnt, nfhlen, i, j;
6001 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_STATEID);
6006 stateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
6007 NFSCL_DEBUG(4, "retoncls=%d stseq=%d\n", *retonclosep,
6008 (int)stateidp->seqid);
6009 stateidp->other[0] = *tl++;
6010 stateidp->other[1] = *tl++;
6011 stateidp->other[2] = *tl++;
6012 cnt = fxdr_unsigned(int, *tl);
6013 NFSCL_DEBUG(4, "layg cnt=%d\n", cnt);
6014 if (cnt <= 0 || cnt > 10000) {
6015 /* Don't accept more than 10000 layouts in reply. */
6016 error = NFSERR_BADXDR;
6019 for (i = 0; i < cnt; i++) {
6020 /* Dissect all the way to the file handle cnt. */
6021 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_HYPER +
6022 6 * NFSX_UNSIGNED + NFSX_V4DEVICEID);
6023 fhcnt = fxdr_unsigned(int, *(tl + 11 +
6024 NFSX_V4DEVICEID / NFSX_UNSIGNED));
6025 NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt);
6026 if (fhcnt < 0 || fhcnt > 100) {
6027 /* Don't accept more than 100 file handles. */
6028 error = NFSERR_BADXDR;
6032 flp = malloc(sizeof(*flp) + (fhcnt - 1) *
6033 sizeof(struct nfsfh *), M_NFSFLAYOUT, M_WAITOK);
6035 flp = malloc(sizeof(*flp), M_NFSFLAYOUT, M_WAITOK);
6036 flp->nfsfl_flags = 0;
6037 flp->nfsfl_fhcnt = 0;
6038 flp->nfsfl_devp = NULL;
6039 flp->nfsfl_off = fxdr_hyper(tl); tl += 2;
6040 retlen = fxdr_hyper(tl); tl += 2;
6041 if (flp->nfsfl_off + retlen < flp->nfsfl_off)
6042 flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off;
6044 flp->nfsfl_end = flp->nfsfl_off + retlen;
6045 flp->nfsfl_iomode = fxdr_unsigned(int, *tl++);
6046 if (gotiomode == -1)
6047 gotiomode = flp->nfsfl_iomode;
6048 if (fxdr_unsigned(int, *tl++) != NFSLAYOUT_NFSV4_1_FILES) {
6049 printf("NFSv4.1: got non-files layout\n");
6050 error = NFSERR_BADXDR;
6053 NFSBCOPY(++tl, flp->nfsfl_dev, NFSX_V4DEVICEID);
6054 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
6055 flp->nfsfl_util = fxdr_unsigned(uint32_t, *tl++);
6056 NFSCL_DEBUG(4, "flutil=0x%x\n", flp->nfsfl_util);
6057 flp->nfsfl_stripe1 = fxdr_unsigned(uint32_t, *tl++);
6058 flp->nfsfl_patoff = fxdr_hyper(tl); tl += 2;
6059 if (fxdr_unsigned(int, *tl) != fhcnt) {
6060 printf("EEK! bad fhcnt\n");
6061 error = NFSERR_BADXDR;
6064 for (j = 0; j < fhcnt; j++) {
6065 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
6066 nfhlen = fxdr_unsigned(int, *tl);
6067 if (nfhlen <= 0 || nfhlen > NFSX_V4FHMAX) {
6068 error = NFSERR_BADXDR;
6071 nfhp = malloc(sizeof(*nfhp) + nfhlen - 1, M_NFSFH,
6073 flp->nfsfl_fh[j] = nfhp;
6075 nfhp->nfh_len = nfhlen;
6076 NFSM_DISSECT(cp, uint8_t *, NFSM_RNDUP(nfhlen));
6077 NFSBCOPY(cp, nfhp->nfh_fh, nfhlen);
6079 if (flp->nfsfl_iomode == gotiomode) {
6080 /* Keep the list in increasing offset order. */
6081 tflp = LIST_FIRST(flhp);
6083 while (tflp != NULL &&
6084 tflp->nfsfl_off < flp->nfsfl_off) {
6086 tflp = LIST_NEXT(tflp, nfsfl_list);
6088 if (prevflp == NULL)
6089 LIST_INSERT_HEAD(flhp, flp, nfsfl_list);
6091 LIST_INSERT_AFTER(prevflp, flp,
6094 printf("nfscl_layoutget(): got wrong iomode\n");
6095 nfscl_freeflayout(flp);
6100 if (error != 0 && flp != NULL)
6101 nfscl_freeflayout(flp);
6106 * Similar to nfsrpc_getlayout(), except that it uses nfsrpc_openlayget(),
6107 * so that it does both an Open and a Layoutget.
6110 nfsrpc_getopenlayout(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp,
6111 int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode,
6112 struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp,
6113 struct ucred *cred, NFSPROC_T *p)
6115 struct nfscllayout *lyp;
6116 struct nfsclflayout *flp;
6117 struct nfsclflayouthead flh;
6118 int error, islocked, layoutlen, recalled, retonclose, usecurstateid;
6120 nfsv4stateid_t stateid;
6121 struct nfsclsession *tsep;
6125 * If lyp is returned non-NULL, there will be a refcnt (shared lock)
6126 * on it, iff flp != NULL or a lock (exclusive lock) on it iff
6129 lyp = nfscl_getlayout(nmp->nm_clp, newfhp, newfhlen, 0, &flp,
6131 NFSCL_DEBUG(4, "nfsrpc_getopenlayout nfscl_getlayout lyp=%p\n", lyp);
6134 else if (flp != NULL)
6138 if ((lyp == NULL || flp == NULL) && recalled == 0) {
6140 tsep = nfsmnt_mdssession(nmp);
6141 layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID +
6147 stateid.seqid = lyp->nfsly_stateid.seqid;
6148 stateid.other[0] = lyp->nfsly_stateid.other[0];
6149 stateid.other[1] = lyp->nfsly_stateid.other[1];
6150 stateid.other[2] = lyp->nfsly_stateid.other[2];
6152 error = nfsrpc_openlayoutrpc(nmp, vp, nfhp, fhlen,
6153 newfhp, newfhlen, mode, op, name, namelen,
6154 dpp, &stateid, usecurstateid, layoutlen,
6155 &retonclose, &flh, &laystat, cred, p);
6156 NFSCL_DEBUG(4, "aft nfsrpc_openlayoutrpc laystat=%d err=%d\n",
6158 laystat = nfsrpc_layoutgetres(nmp, vp, newfhp, newfhlen,
6159 &stateid, retonclose, NULL, &lyp, &flh, laystat, &islocked,
6162 error = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp, newfhlen,
6163 mode, op, name, namelen, dpp, 0, 0, cred, p, 0, 0);
6165 nfscl_rellayout(lyp, 1);
6166 else if (islocked == 1)
6167 nfscl_rellayout(lyp, 0);
6172 * This function does an Open+LayoutGet for an NFSv4.1 mount with pNFS
6173 * enabled, only for the CLAIM_NULL case. All other NFSv4 Opens are
6174 * handled by nfsrpc_openrpc().
6175 * For the case where op == NULL, dvp is the directory. When op != NULL, it
6179 nfsrpc_openlayoutrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp,
6180 int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode,
6181 struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp,
6182 nfsv4stateid_t *stateidp, int usecurstateid,
6183 int layoutlen, int *retonclosep, struct nfsclflayouthead *flhp,
6184 int *laystatp, struct ucred *cred, NFSPROC_T *p)
6187 struct nfsrv_descript nfsd, *nd = &nfsd;
6188 struct nfscldeleg *ndp = NULL;
6189 struct nfsvattr nfsva;
6190 struct nfsclsession *tsep;
6191 uint32_t rflags, deleg;
6192 nfsattrbit_t attrbits;
6193 int error, ret, acesize, limitby, iomode;
6197 nfscl_reqstart(nd, NFSPROC_OPENLAYGET, nmp, nfhp, fhlen, NULL, NULL);
6198 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
6199 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
6200 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
6201 *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
6202 tsep = nfsmnt_mdssession(nmp);
6203 *tl++ = tsep->nfsess_clientid.lval[0];
6204 *tl = tsep->nfsess_clientid.lval[1];
6205 nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN);
6206 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
6207 *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE);
6208 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
6209 nfsm_strtom(nd, name, namelen);
6210 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
6211 *tl = txdr_unsigned(NFSV4OP_GETATTR);
6212 NFSZERO_ATTRBIT(&attrbits);
6213 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
6214 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY);
6215 nfsrv_putattrbit(nd, &attrbits);
6216 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
6217 *tl = txdr_unsigned(NFSV4OP_LAYOUTGET);
6218 if ((mode & NFSV4OPEN_ACCESSWRITE) != 0)
6219 iomode = NFSLAYOUTIOMODE_RW;
6221 iomode = NFSLAYOUTIOMODE_READ;
6222 nfsrv_setuplayoutget(nd, iomode, 0, UINT64_MAX, 0, stateidp,
6223 layoutlen, usecurstateid);
6224 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
6225 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
6228 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
6229 if (nd->nd_repstat != 0)
6230 *laystatp = nd->nd_repstat;
6231 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
6232 /* ND_NOMOREDATA will be set if the Open operation failed. */
6233 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
6235 op->nfso_stateid.seqid = *tl++;
6236 op->nfso_stateid.other[0] = *tl++;
6237 op->nfso_stateid.other[1] = *tl++;
6238 op->nfso_stateid.other[2] = *tl;
6239 rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
6240 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
6243 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
6244 deleg = fxdr_unsigned(u_int32_t, *tl);
6245 if (deleg == NFSV4OPEN_DELEGATEREAD ||
6246 deleg == NFSV4OPEN_DELEGATEWRITE) {
6247 if (!(op->nfso_own->nfsow_clp->nfsc_flags &
6248 NFSCLFLAGS_FIRSTDELEG))
6249 op->nfso_own->nfsow_clp->nfsc_flags |=
6250 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
6251 ndp = malloc(sizeof(struct nfscldeleg) + newfhlen,
6252 M_NFSCLDELEG, M_WAITOK);
6253 LIST_INIT(&ndp->nfsdl_owner);
6254 LIST_INIT(&ndp->nfsdl_lock);
6255 ndp->nfsdl_clp = op->nfso_own->nfsow_clp;
6256 ndp->nfsdl_fhlen = newfhlen;
6257 NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen);
6258 newnfs_copyincred(cred, &ndp->nfsdl_cred);
6259 nfscl_lockinit(&ndp->nfsdl_rwlock);
6260 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
6262 ndp->nfsdl_stateid.seqid = *tl++;
6263 ndp->nfsdl_stateid.other[0] = *tl++;
6264 ndp->nfsdl_stateid.other[1] = *tl++;
6265 ndp->nfsdl_stateid.other[2] = *tl++;
6266 ret = fxdr_unsigned(int, *tl);
6267 if (deleg == NFSV4OPEN_DELEGATEWRITE) {
6268 ndp->nfsdl_flags = NFSCLDL_WRITE;
6270 * Indicates how much the file can grow.
6272 NFSM_DISSECT(tl, u_int32_t *,
6274 limitby = fxdr_unsigned(int, *tl++);
6276 case NFSV4OPEN_LIMITSIZE:
6277 ndp->nfsdl_sizelimit = fxdr_hyper(tl);
6279 case NFSV4OPEN_LIMITBLOCKS:
6280 ndp->nfsdl_sizelimit =
6281 fxdr_unsigned(u_int64_t, *tl++);
6282 ndp->nfsdl_sizelimit *=
6283 fxdr_unsigned(u_int64_t, *tl);
6286 error = NFSERR_BADXDR;
6290 ndp->nfsdl_flags = NFSCLDL_READ;
6292 ndp->nfsdl_flags |= NFSCLDL_RECALL;
6293 error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, &ret,
6297 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
6298 error = NFSERR_BADXDR;
6301 if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) != 0 ||
6302 nfscl_assumeposixlocks)
6303 op->nfso_posixlock = 1;
6305 op->nfso_posixlock = 0;
6306 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
6307 /* If the 2nd element == NFS_OK, the Getattr succeeded. */
6309 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
6310 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
6311 NULL, NULL, NULL, p, cred);
6315 ndp->nfsdl_change = nfsva.na_filerev;
6316 ndp->nfsdl_modtime = nfsva.na_mtime;
6317 ndp->nfsdl_flags |= NFSCLDL_MODTIMESET;
6322 * At this point, the Open has succeeded, so set
6323 * nd_repstat = NFS_OK. If the Layoutget failed,
6324 * this function just won't return a layout.
6326 if (nd->nd_repstat == 0) {
6327 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
6328 *laystatp = fxdr_unsigned(int, *++tl);
6329 if (*laystatp == 0) {
6330 error = nfsrv_parselayoutget(nd,
6331 stateidp, retonclosep, flhp);
6336 nd->nd_repstat = 0; /* Return 0 for Open. */
6339 if (nd->nd_repstat != 0 && error == 0)
6340 error = nd->nd_repstat;
6342 free(ndp, M_NFSCLDELEG);
6343 mbuf_freem(nd->nd_mrep);
6348 * Similar nfsrpc_createv4(), but also does the LayoutGet operation.
6349 * Used only for mounts with pNFS enabled.
6352 nfsrpc_createlayout(vnode_t dvp, char *name, int namelen, struct vattr *vap,
6353 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp,
6354 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
6355 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
6356 int *dattrflagp, void *dstuff, int *unlockedp, nfsv4stateid_t *stateidp,
6357 int usecurstateid, int layoutlen, int *retonclosep,
6358 struct nfsclflayouthead *flhp, int *laystatp)
6361 int error = 0, deleg, newone, ret, acesize, limitby;
6362 struct nfsrv_descript nfsd, *nd = &nfsd;
6363 struct nfsclopen *op;
6364 struct nfscldeleg *dp = NULL;
6367 struct nfsclsession *tsep;
6368 nfsattrbit_t attrbits;
6369 nfsv4stateid_t stateid;
6371 struct nfsmount *nmp;
6373 nmp = VFSTONFS(dvp->v_mount);
6381 if (namelen > NFS_MAXNAMLEN)
6382 return (ENAMETOOLONG);
6383 NFSCL_REQSTART(nd, NFSPROC_CREATELAYGET, dvp);
6385 * For V4, this is actually an Open op.
6387 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
6388 *tl++ = txdr_unsigned(owp->nfsow_seqid);
6389 *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
6390 NFSV4OPEN_ACCESSREAD);
6391 *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE);
6392 tsep = nfsmnt_mdssession(nmp);
6393 *tl++ = tsep->nfsess_clientid.lval[0];
6394 *tl = tsep->nfsess_clientid.lval[1];
6395 nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN);
6396 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
6397 *tl++ = txdr_unsigned(NFSV4OPEN_CREATE);
6398 if ((fmode & O_EXCL) != 0) {
6399 if (NFSHASSESSPERSIST(nmp)) {
6400 /* Use GUARDED for persistent sessions. */
6401 *tl = txdr_unsigned(NFSCREATE_GUARDED);
6402 nfscl_fillsattr(nd, vap, dvp, 0, 0);
6404 /* Otherwise, use EXCLUSIVE4_1. */
6405 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41);
6406 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
6407 *tl++ = cverf.lval[0];
6408 *tl = cverf.lval[1];
6409 nfscl_fillsattr(nd, vap, dvp, 0, 0);
6412 *tl = txdr_unsigned(NFSCREATE_UNCHECKED);
6413 nfscl_fillsattr(nd, vap, dvp, 0, 0);
6415 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
6416 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
6417 nfsm_strtom(nd, name, namelen);
6418 /* Get the new file's handle and attributes, plus save the FH. */
6419 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
6420 *tl++ = txdr_unsigned(NFSV4OP_SAVEFH);
6421 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
6422 *tl = txdr_unsigned(NFSV4OP_GETATTR);
6423 NFSGETATTR_ATTRBIT(&attrbits);
6424 nfsrv_putattrbit(nd, &attrbits);
6425 /* Get the directory's post-op attributes. */
6426 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
6427 *tl = txdr_unsigned(NFSV4OP_PUTFH);
6428 nfsm_fhtom(nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0);
6429 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
6430 *tl = txdr_unsigned(NFSV4OP_GETATTR);
6431 nfsrv_putattrbit(nd, &attrbits);
6432 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
6433 *tl++ = txdr_unsigned(NFSV4OP_RESTOREFH);
6434 *tl = txdr_unsigned(NFSV4OP_LAYOUTGET);
6435 nfsrv_setuplayoutget(nd, NFSLAYOUTIOMODE_RW, 0, UINT64_MAX, 0, stateidp,
6436 layoutlen, usecurstateid);
6437 error = nfscl_request(nd, dvp, p, cred, dstuff);
6440 NFSCL_DEBUG(4, "nfsrpc_createlayout stat=%d err=%d\n", nd->nd_repstat,
6442 if (nd->nd_repstat != 0)
6443 *laystatp = nd->nd_repstat;
6444 NFSCL_INCRSEQID(owp->nfsow_seqid, nd);
6445 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
6446 NFSCL_DEBUG(4, "nfsrpc_createlayout open succeeded\n");
6447 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
6449 stateid.seqid = *tl++;
6450 stateid.other[0] = *tl++;
6451 stateid.other[1] = *tl++;
6452 stateid.other[2] = *tl;
6453 rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
6454 nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
6455 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
6456 deleg = fxdr_unsigned(int, *tl);
6457 if (deleg == NFSV4OPEN_DELEGATEREAD ||
6458 deleg == NFSV4OPEN_DELEGATEWRITE) {
6459 if (!(owp->nfsow_clp->nfsc_flags &
6460 NFSCLFLAGS_FIRSTDELEG))
6461 owp->nfsow_clp->nfsc_flags |=
6462 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
6463 dp = malloc(sizeof(struct nfscldeleg) + NFSX_V4FHMAX,
6464 M_NFSCLDELEG, M_WAITOK);
6465 LIST_INIT(&dp->nfsdl_owner);
6466 LIST_INIT(&dp->nfsdl_lock);
6467 dp->nfsdl_clp = owp->nfsow_clp;
6468 newnfs_copyincred(cred, &dp->nfsdl_cred);
6469 nfscl_lockinit(&dp->nfsdl_rwlock);
6470 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
6472 dp->nfsdl_stateid.seqid = *tl++;
6473 dp->nfsdl_stateid.other[0] = *tl++;
6474 dp->nfsdl_stateid.other[1] = *tl++;
6475 dp->nfsdl_stateid.other[2] = *tl++;
6476 ret = fxdr_unsigned(int, *tl);
6477 if (deleg == NFSV4OPEN_DELEGATEWRITE) {
6478 dp->nfsdl_flags = NFSCLDL_WRITE;
6480 * Indicates how much the file can grow.
6482 NFSM_DISSECT(tl, u_int32_t *,
6484 limitby = fxdr_unsigned(int, *tl++);
6486 case NFSV4OPEN_LIMITSIZE:
6487 dp->nfsdl_sizelimit = fxdr_hyper(tl);
6489 case NFSV4OPEN_LIMITBLOCKS:
6490 dp->nfsdl_sizelimit =
6491 fxdr_unsigned(u_int64_t, *tl++);
6492 dp->nfsdl_sizelimit *=
6493 fxdr_unsigned(u_int64_t, *tl);
6496 error = NFSERR_BADXDR;
6500 dp->nfsdl_flags = NFSCLDL_READ;
6503 dp->nfsdl_flags |= NFSCLDL_RECALL;
6504 error = nfsrv_dissectace(nd, &dp->nfsdl_ace, &ret,
6508 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
6509 error = NFSERR_BADXDR;
6513 /* Now, we should have the status for the SaveFH. */
6514 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
6516 NFSCL_DEBUG(4, "nfsrpc_createlayout SaveFH ok\n");
6518 * Now, process the GetFH and Getattr for the newly
6519 * created file. nfscl_mtofh() will set
6520 * ND_NOMOREDATA if these weren't successful.
6522 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
6523 NFSCL_DEBUG(4, "aft nfscl_mtofh err=%d\n", error);
6527 nd->nd_flag |= ND_NOMOREDATA;
6528 /* Now we have the PutFH and Getattr for the directory. */
6529 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
6530 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
6532 nd->nd_flag |= ND_NOMOREDATA;
6534 NFSM_DISSECT(tl, uint32_t *, 2 *
6537 nd->nd_flag |= ND_NOMOREDATA;
6540 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
6541 /* Load the directory attributes. */
6542 error = nfsm_loadattr(nd, dnap);
6543 NFSCL_DEBUG(4, "aft nfsm_loadattr err=%d\n", error);
6547 if (dp != NULL && *attrflagp != 0) {
6548 dp->nfsdl_change = nnap->na_filerev;
6549 dp->nfsdl_modtime = nnap->na_mtime;
6550 dp->nfsdl_flags |= NFSCLDL_MODTIMESET;
6553 * We can now complete the Open state.
6557 dp->nfsdl_fhlen = nfhp->nfh_len;
6558 NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh,
6562 * Get an Open structure that will be
6563 * attached to the OpenOwner, acquired already.
6565 error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len,
6566 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0,
6567 cred, p, NULL, &op, &newone, NULL, 0);
6570 op->nfso_stateid = stateid;
6571 newnfs_copyincred(cred, &op->nfso_cred);
6573 nfscl_openrelease(nmp, op, error, newone);
6576 /* Now, handle the RestoreFH and LayoutGet. */
6577 if (nd->nd_repstat == 0) {
6578 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
6579 *laystatp = fxdr_unsigned(int, *(tl + 3));
6580 if (*laystatp == 0) {
6581 error = nfsrv_parselayoutget(nd,
6582 stateidp, retonclosep, flhp);
6586 NFSCL_DEBUG(4, "aft nfsrv_parselayout err=%d\n",
6592 if (nd->nd_repstat != 0 && error == 0)
6593 error = nd->nd_repstat;
6594 if (error == NFSERR_STALECLIENTID || error == NFSERR_BADSESSION)
6595 nfscl_initiate_recovery(owp->nfsow_clp);
6597 NFSCL_DEBUG(4, "eo nfsrpc_createlayout err=%d\n", error);
6601 free(dp, M_NFSCLDELEG);
6602 mbuf_freem(nd->nd_mrep);
6607 * Similar to nfsrpc_getopenlayout(), except that it used for the Create case.
6610 nfsrpc_getcreatelayout(vnode_t dvp, char *name, int namelen, struct vattr *vap,
6611 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp,
6612 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
6613 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
6614 int *dattrflagp, void *dstuff, int *unlockedp)
6616 struct nfscllayout *lyp;
6617 struct nfsclflayouthead flh;
6619 struct nfsclsession *tsep;
6620 struct nfsmount *nmp;
6621 nfsv4stateid_t stateid;
6622 int error, layoutlen, retonclose, laystat;
6625 nmp = VFSTONFS(dvp->v_mount);
6627 tsep = nfsmnt_mdssession(nmp);
6628 layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID + 3 * NFSX_UNSIGNED);
6629 error = nfsrpc_createlayout(dvp, name, namelen, vap, cverf, fmode,
6630 owp, dpp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp,
6631 dstuff, unlockedp, &stateid, 1, layoutlen, &retonclose, &flh,
6633 NFSCL_DEBUG(4, "aft nfsrpc_createlayoutrpc laystat=%d err=%d\n",
6638 laystat = nfsrpc_layoutgetres(nmp, dvp, nfhp->nfh_fh,
6639 nfhp->nfh_len, &stateid, retonclose, NULL, &lyp, &flh,
6640 laystat, NULL, cred, p);
6642 laystat = nfsrpc_layoutgetres(nmp, dvp, NULL, 0, &stateid,
6643 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)