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 <fs/nfs/nfsport.h>
51 extern int nfs_numnfscbd;
52 extern struct timeval nfsboottime;
53 extern u_int32_t newnfs_false, newnfs_true;
54 extern nfstype nfsv34_type[9];
55 extern int nfsrv_useacl;
56 extern char nfsv4_callbackaddr[INET6_ADDRSTRLEN];
58 int nfstest_outofseq = 0;
59 int nfscl_assumeposixlocks = 1;
60 int nfscl_enablecallb = 0;
61 short nfsv4_cbport = NFSV4_CBPORT;
62 int nfstest_openallsetattr = 0;
63 #endif /* !APPLEKEXT */
65 #define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1))
67 static int nfsrpc_setattrrpc(vnode_t , struct vattr *, nfsv4stateid_t *,
68 struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, void *);
69 static int nfsrpc_readrpc(vnode_t , struct uio *, struct ucred *,
70 nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *, void *);
71 static int nfsrpc_writerpc(vnode_t , struct uio *, int *, u_char *,
72 struct ucred *, nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *,
74 static int nfsrpc_createv23(vnode_t , char *, int, struct vattr *,
75 nfsquad_t, int, struct ucred *, NFSPROC_T *, struct nfsvattr *,
76 struct nfsvattr *, struct nfsfh **, int *, int *, void *);
77 static int nfsrpc_createv4(vnode_t , char *, int, struct vattr *,
78 nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, struct ucred *,
79 NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, struct nfsfh **, int *,
80 int *, void *, int *);
81 static int nfsrpc_locku(struct nfsrv_descript *, struct nfsmount *,
82 struct nfscllockowner *, u_int64_t, u_int64_t,
83 u_int32_t, struct ucred *, NFSPROC_T *, int);
84 #ifdef NFS4_ACL_EXTATTR_NAME
85 static int nfsrpc_setaclrpc(vnode_t, struct ucred *, NFSPROC_T *,
86 struct acl *, nfsv4stateid_t *, void *);
90 * nfs null call from vfs.
93 nfsrpc_null(vnode_t vp, struct ucred *cred, NFSPROC_T *p)
96 struct nfsrv_descript nfsd, *nd = &nfsd;
98 NFSCL_REQSTART(nd, NFSPROC_NULL, vp);
99 error = nfscl_request(nd, vp, p, cred, NULL);
100 if (nd->nd_repstat && !error)
101 error = nd->nd_repstat;
102 mbuf_freem(nd->nd_mrep);
108 * For nfs version 3 and 4, use the access rpc to check accessibility. If file
109 * modes are changed on the server, accesses might still fail later.
112 nfsrpc_access(vnode_t vp, int acmode, struct ucred *cred,
113 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp)
116 u_int32_t mode, rmode;
119 mode = NFSACCESS_READ;
122 if (vnode_vtype(vp) == VDIR) {
124 mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND |
127 mode |= NFSACCESS_LOOKUP;
130 mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND);
132 mode |= NFSACCESS_EXECUTE;
136 * Now, just call nfsrpc_accessrpc() to do the actual RPC.
138 error = nfsrpc_accessrpc(vp, mode, cred, p, nap, attrflagp, &rmode,
142 * The NFS V3 spec does not clarify whether or not
143 * the returned access bits can be a superset of
144 * the ones requested, so...
146 if (!error && (rmode & mode) != mode)
152 * The actual rpc, separated out for Darwin.
155 nfsrpc_accessrpc(vnode_t vp, u_int32_t mode, struct ucred *cred,
156 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, u_int32_t *rmodep,
160 u_int32_t supported, rmode;
162 struct nfsrv_descript nfsd, *nd = &nfsd;
163 nfsattrbit_t attrbits;
167 NFSCL_REQSTART(nd, NFSPROC_ACCESS, vp);
168 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
169 *tl = txdr_unsigned(mode);
170 if (nd->nd_flag & ND_NFSV4) {
172 * And do a Getattr op.
174 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
175 *tl = txdr_unsigned(NFSV4OP_GETATTR);
176 NFSGETATTR_ATTRBIT(&attrbits);
177 (void) nfsrv_putattrbit(nd, &attrbits);
179 error = nfscl_request(nd, vp, p, cred, stuff);
182 if (nd->nd_flag & ND_NFSV3) {
183 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
187 if (!nd->nd_repstat) {
188 if (nd->nd_flag & ND_NFSV4) {
189 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
190 supported = fxdr_unsigned(u_int32_t, *tl++);
192 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
194 rmode = fxdr_unsigned(u_int32_t, *tl);
195 if (nd->nd_flag & ND_NFSV4)
196 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
199 * It's not obvious what should be done about
200 * unsupported access modes. For now, be paranoid
201 * and clear the unsupported ones.
206 error = nd->nd_repstat;
208 mbuf_freem(nd->nd_mrep);
216 nfsrpc_open(vnode_t vp, int amode, struct ucred *cred, NFSPROC_T *p)
218 struct nfsclopen *op;
219 struct nfscldeleg *dp;
221 struct nfsnode *np = VTONFS(vp);
222 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
223 u_int32_t mode, clidrev;
224 int ret, newone, error, expireret = 0, retrycnt;
227 * For NFSv4, Open Ops are only done on Regular Files.
229 if (vnode_vtype(vp) != VREG)
233 mode |= NFSV4OPEN_ACCESSREAD;
235 mode |= NFSV4OPEN_ACCESSWRITE;
240 { char name[100]; int namel;
241 namel = (np->n_v4->n4_namelen < 100) ? np->n_v4->n4_namelen : 99;
242 bcopy(NFS4NODENAME(np->n_v4), name, namel);
244 printf("rpcopen p=0x%x name=%s",p->p_pid,name);
245 if (nfhp->nfh_len > 0) printf(" fh=0x%x\n",nfhp->nfh_fh[12]);
246 else printf(" fhl=0\n");
251 error = nfscl_open(vp, nfhp->nfh_fh, nfhp->nfh_len, mode, 1,
252 cred, p, NULL, &op, &newone, &ret, 1);
256 if (nmp->nm_clp != NULL)
257 clidrev = nmp->nm_clp->nfsc_clientidrev;
260 if (ret == NFSCLOPEN_DOOPEN) {
261 if (np->n_v4 != NULL) {
262 error = nfsrpc_openrpc(nmp, vp, np->n_v4->n4_data,
263 np->n_v4->n4_fhlen, np->n_fhp->nfh_fh,
264 np->n_fhp->nfh_len, mode, op,
265 NFS4NODENAME(np->n_v4), np->n_v4->n4_namelen, &dp,
266 0, 0x0, cred, p, 0, 0);
269 OSBitAndAtomic((int32_t)~NDELEGMOD, (UInt32 *)&np->n_flag);
272 np->n_flag &= ~NDELEGMOD;
275 (void) nfscl_deleg(nmp->nm_mountp,
276 op->nfso_own->nfsow_clp,
277 nfhp->nfh_fh, nfhp->nfh_len, cred, p, &dp);
282 newnfs_copyincred(cred, &op->nfso_cred);
283 } else if (ret == NFSCLOPEN_SETCRED)
285 * This is a new local open on a delegation. It needs
286 * to have credentials so that an open can be done
287 * against the server during recovery.
289 newnfs_copyincred(cred, &op->nfso_cred);
292 * nfso_opencnt is the count of how many VOP_OPEN()s have
293 * been done on this Open successfully and a VOP_CLOSE()
294 * is expected for each of these.
295 * If error is non-zero, don't increment it, since the Open
296 * hasn't succeeded yet.
300 nfscl_openrelease(op, error, newone);
301 if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
302 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY) {
303 (void) nfs_catnap(PZERO, error, "nfs_open");
304 } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID)
306 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
309 } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
310 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
311 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
312 expireret == 0 && clidrev != 0 && retrycnt < 4));
313 if (error && retrycnt >= 4)
319 * the actual open rpc
322 nfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen,
323 u_int8_t *newfhp, int newfhlen, u_int32_t mode, struct nfsclopen *op,
324 u_int8_t *name, int namelen, struct nfscldeleg **dpp,
325 int reclaim, u_int32_t delegtype, struct ucred *cred, NFSPROC_T *p,
326 int syscred, int recursed)
329 struct nfsrv_descript nfsd, *nd = &nfsd;
330 struct nfscldeleg *dp, *ndp = NULL;
331 struct nfsvattr nfsva;
332 u_int32_t rflags, deleg;
333 nfsattrbit_t attrbits;
334 int error, ret, acesize, limitby;
338 nfscl_reqstart(nd, NFSPROC_OPEN, nmp, nfhp, fhlen, NULL);
339 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
340 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
341 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
342 *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
343 *tl++ = op->nfso_own->nfsow_clp->nfsc_clientid.lval[0];
344 *tl = op->nfso_own->nfsow_clp->nfsc_clientid.lval[1];
345 (void) nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN);
346 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
347 *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE);
349 *tl = txdr_unsigned(NFSV4OPEN_CLAIMPREVIOUS);
350 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
351 *tl = txdr_unsigned(delegtype);
354 *tl = txdr_unsigned(NFSV4OPEN_CLAIMDELEGATECUR);
355 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
356 *tl++ = dp->nfsdl_stateid.seqid;
357 *tl++ = dp->nfsdl_stateid.other[0];
358 *tl++ = dp->nfsdl_stateid.other[1];
359 *tl = dp->nfsdl_stateid.other[2];
361 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
363 (void) nfsm_strtom(nd, name, namelen);
365 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
366 *tl = txdr_unsigned(NFSV4OP_GETATTR);
367 NFSZERO_ATTRBIT(&attrbits);
368 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
369 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY);
370 (void) nfsrv_putattrbit(nd, &attrbits);
372 nd->nd_flag |= ND_USEGSSNAME;
373 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
374 NFS_PROG, NFS_VER4, NULL, 1, NULL);
377 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
378 if (!nd->nd_repstat) {
379 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
381 op->nfso_stateid.seqid = *tl++;
382 op->nfso_stateid.other[0] = *tl++;
383 op->nfso_stateid.other[1] = *tl++;
384 op->nfso_stateid.other[2] = *tl;
385 rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
386 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
389 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
390 deleg = fxdr_unsigned(u_int32_t, *tl);
391 if (deleg == NFSV4OPEN_DELEGATEREAD ||
392 deleg == NFSV4OPEN_DELEGATEWRITE) {
393 if (!(op->nfso_own->nfsow_clp->nfsc_flags &
394 NFSCLFLAGS_FIRSTDELEG))
395 op->nfso_own->nfsow_clp->nfsc_flags |=
396 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
397 MALLOC(ndp, struct nfscldeleg *,
398 sizeof (struct nfscldeleg) + newfhlen,
399 M_NFSCLDELEG, M_WAITOK);
400 LIST_INIT(&ndp->nfsdl_owner);
401 LIST_INIT(&ndp->nfsdl_lock);
402 ndp->nfsdl_clp = op->nfso_own->nfsow_clp;
403 ndp->nfsdl_fhlen = newfhlen;
404 NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen);
405 newnfs_copyincred(cred, &ndp->nfsdl_cred);
406 nfscl_lockinit(&ndp->nfsdl_rwlock);
407 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
409 ndp->nfsdl_stateid.seqid = *tl++;
410 ndp->nfsdl_stateid.other[0] = *tl++;
411 ndp->nfsdl_stateid.other[1] = *tl++;
412 ndp->nfsdl_stateid.other[2] = *tl++;
413 ret = fxdr_unsigned(int, *tl);
414 if (deleg == NFSV4OPEN_DELEGATEWRITE) {
415 ndp->nfsdl_flags = NFSCLDL_WRITE;
417 * Indicates how much the file can grow.
419 NFSM_DISSECT(tl, u_int32_t *,
421 limitby = fxdr_unsigned(int, *tl++);
423 case NFSV4OPEN_LIMITSIZE:
424 ndp->nfsdl_sizelimit = fxdr_hyper(tl);
426 case NFSV4OPEN_LIMITBLOCKS:
427 ndp->nfsdl_sizelimit =
428 fxdr_unsigned(u_int64_t, *tl++);
429 ndp->nfsdl_sizelimit *=
430 fxdr_unsigned(u_int64_t, *tl);
433 error = NFSERR_BADXDR;
437 ndp->nfsdl_flags = NFSCLDL_READ;
440 ndp->nfsdl_flags |= NFSCLDL_RECALL;
441 error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, &ret,
445 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
446 error = NFSERR_BADXDR;
449 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
450 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
451 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
452 NULL, NULL, NULL, p, cred);
456 ndp->nfsdl_change = nfsva.na_filerev;
457 ndp->nfsdl_modtime = nfsva.na_mtime;
458 ndp->nfsdl_flags |= NFSCLDL_MODTIMESET;
460 if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM)) {
462 ret = nfsrpc_openconfirm(vp, newfhp, newfhlen, op,
464 if (ret == NFSERR_DELAY)
465 (void) nfs_catnap(PZERO, ret, "nfs_open");
466 } while (ret == NFSERR_DELAY);
469 if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) ||
470 nfscl_assumeposixlocks)
471 op->nfso_posixlock = 1;
473 op->nfso_posixlock = 0;
476 * If the server is handing out delegations, but we didn't
477 * get one because an OpenConfirm was required, try the
478 * Open again, to get a delegation. This is a harmless no-op,
479 * from a server's point of view.
481 if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM) &&
482 (op->nfso_own->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG)
483 && !error && dp == NULL && ndp == NULL && !recursed) {
485 ret = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp,
486 newfhlen, mode, op, name, namelen, &ndp, 0, 0x0,
487 cred, p, syscred, 1);
488 if (ret == NFSERR_DELAY)
489 (void) nfs_catnap(PZERO, ret, "nfs_open2");
490 } while (ret == NFSERR_DELAY);
493 FREE((caddr_t)ndp, M_NFSCLDELEG);
494 if (ret == NFSERR_STALECLIENTID ||
495 ret == NFSERR_STALEDONTRECOVER)
500 if (nd->nd_repstat != 0 && error == 0)
501 error = nd->nd_repstat;
502 if (error == NFSERR_STALECLIENTID)
503 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
507 else if (ndp != NULL)
508 FREE((caddr_t)ndp, M_NFSCLDELEG);
509 mbuf_freem(nd->nd_mrep);
517 nfsrpc_opendowngrade(vnode_t vp, u_int32_t mode, struct nfsclopen *op,
518 struct ucred *cred, NFSPROC_T *p)
521 struct nfsrv_descript nfsd, *nd = &nfsd;
524 NFSCL_REQSTART(nd, NFSPROC_OPENDOWNGRADE, vp);
525 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
526 *tl++ = op->nfso_stateid.seqid;
527 *tl++ = op->nfso_stateid.other[0];
528 *tl++ = op->nfso_stateid.other[1];
529 *tl++ = op->nfso_stateid.other[2];
530 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
531 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
532 *tl = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
533 error = nfscl_request(nd, vp, p, cred, NULL);
536 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
537 if (!nd->nd_repstat) {
538 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
539 op->nfso_stateid.seqid = *tl++;
540 op->nfso_stateid.other[0] = *tl++;
541 op->nfso_stateid.other[1] = *tl++;
542 op->nfso_stateid.other[2] = *tl;
544 if (nd->nd_repstat && error == 0)
545 error = nd->nd_repstat;
546 if (error == NFSERR_STALESTATEID)
547 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
549 mbuf_freem(nd->nd_mrep);
554 * V4 Close operation.
557 nfsrpc_close(vnode_t vp, int doclose, NFSPROC_T *p)
559 struct nfsclclient *clp;
562 if (vnode_vtype(vp) != VREG)
565 error = nfscl_doclose(vp, &clp, p);
567 error = nfscl_getclose(vp, &clp);
571 nfscl_clientrelease(clp);
579 nfsrpc_doclose(struct nfsmount *nmp, struct nfsclopen *op, NFSPROC_T *p)
581 struct nfsrv_descript nfsd, *nd = &nfsd;
582 struct nfscllockowner *lp;
583 struct nfscllock *lop, *nlop;
585 u_int64_t off = 0, len = 0;
586 u_int32_t type = NFSV4LOCKT_READ;
587 int error, do_unlock, trycnt;
589 tcred = newnfs_getcred();
590 newnfs_copycred(&op->nfso_cred, tcred);
592 * (Theoretically this could be done in the same
593 * compound as the close, but having multiple
594 * sequenced Ops in the same compound might be
595 * too scary for some servers.)
597 if (op->nfso_posixlock) {
600 type = NFSV4LOCKT_READ;
604 * Since this function is only called from VOP_INACTIVE(), no
605 * other thread will be manipulating this Open. As such, the
606 * lock lists are not being changed by other threads, so it should
607 * be safe to do this without locking.
609 LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) {
611 LIST_FOREACH_SAFE(lop, &lp->nfsl_lock, nfslo_list, nlop) {
612 if (op->nfso_posixlock == 0) {
613 off = lop->nfslo_first;
614 len = lop->nfslo_end - lop->nfslo_first;
615 if (lop->nfslo_type == F_WRLCK)
616 type = NFSV4LOCKT_WRITE;
618 type = NFSV4LOCKT_READ;
623 error = nfsrpc_locku(nd, nmp, lp, off,
624 len, type, tcred, p, 0);
625 if ((nd->nd_repstat == NFSERR_GRACE ||
626 nd->nd_repstat == NFSERR_DELAY) &&
628 (void) nfs_catnap(PZERO,
631 } while ((nd->nd_repstat == NFSERR_GRACE ||
632 nd->nd_repstat == NFSERR_DELAY) &&
633 error == 0 && trycnt++ < 5);
634 if (op->nfso_posixlock)
637 nfscl_freelock(lop, 0);
642 * There could be other Opens for different files on the same
643 * OpenOwner, so locking is required.
646 nfscl_lockexcl(&op->nfso_own->nfsow_rwlock, NFSCLSTATEMUTEXPTR);
649 error = nfscl_tryclose(op, tcred, nmp, p);
650 if (error == NFSERR_GRACE)
651 (void) nfs_catnap(PZERO, error, "nfs_close");
652 } while (error == NFSERR_GRACE);
654 nfscl_lockunlock(&op->nfso_own->nfsow_rwlock);
657 * Move the lockowner to nfsc_defunctlockowner,
658 * so the Renew thread will do the ReleaseLockOwner
659 * Op on it later. There might still be other
660 * opens using the same lockowner name.
662 lp = LIST_FIRST(&op->nfso_lock);
664 while (LIST_NEXT(lp, nfsl_list) != NULL)
665 lp = LIST_NEXT(lp, nfsl_list);
666 LIST_PREPEND(&nmp->nm_clp->nfsc_defunctlockowner,
667 &op->nfso_lock, lp, nfsl_list);
668 LIST_INIT(&op->nfso_lock);
670 nfscl_freeopen(op, 0);
676 * The actual Close RPC.
679 nfsrpc_closerpc(struct nfsrv_descript *nd, struct nfsmount *nmp,
680 struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p,
686 nfscl_reqstart(nd, NFSPROC_CLOSE, nmp, op->nfso_fh,
687 op->nfso_fhlen, NULL);
688 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
689 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
690 *tl++ = op->nfso_stateid.seqid;
691 *tl++ = op->nfso_stateid.other[0];
692 *tl++ = op->nfso_stateid.other[1];
693 *tl = op->nfso_stateid.other[2];
695 nd->nd_flag |= ND_USEGSSNAME;
696 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
697 NFS_PROG, NFS_VER4, NULL, 1, NULL);
700 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
701 if (nd->nd_repstat == 0)
702 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
703 error = nd->nd_repstat;
704 if (error == NFSERR_STALESTATEID)
705 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
707 mbuf_freem(nd->nd_mrep);
712 * V4 Open Confirm RPC.
715 nfsrpc_openconfirm(vnode_t vp, u_int8_t *nfhp, int fhlen,
716 struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p)
719 struct nfsrv_descript nfsd, *nd = &nfsd;
722 nfscl_reqstart(nd, NFSPROC_OPENCONFIRM, VFSTONFS(vnode_mount(vp)),
724 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
725 *tl++ = op->nfso_stateid.seqid;
726 *tl++ = op->nfso_stateid.other[0];
727 *tl++ = op->nfso_stateid.other[1];
728 *tl++ = op->nfso_stateid.other[2];
729 *tl = txdr_unsigned(op->nfso_own->nfsow_seqid);
730 error = nfscl_request(nd, vp, p, cred, NULL);
733 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
734 if (!nd->nd_repstat) {
735 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
736 op->nfso_stateid.seqid = *tl++;
737 op->nfso_stateid.other[0] = *tl++;
738 op->nfso_stateid.other[1] = *tl++;
739 op->nfso_stateid.other[2] = *tl;
741 error = nd->nd_repstat;
742 if (error == NFSERR_STALESTATEID)
743 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
745 mbuf_freem(nd->nd_mrep);
750 * Do the setclientid and setclientid confirm RPCs. Called from nfs_statfs()
751 * when a mount has just occurred and when the server replies NFSERR_EXPIRED.
754 nfsrpc_setclient(struct nfsmount *nmp, struct nfsclclient *clp,
755 struct ucred *cred, NFSPROC_T *p)
758 struct nfsrv_descript nfsd;
759 struct nfsrv_descript *nd = &nfsd;
760 nfsattrbit_t attrbits;
761 u_int8_t *cp = NULL, *cp2, addr[INET6_ADDRSTRLEN + 9];
763 int error, isinet6 = 0, callblen;
766 static u_int32_t rev = 0;
768 if (nfsboottime.tv_sec == 0)
769 NFSSETBOOTTIME(nfsboottime);
770 nfscl_reqstart(nd, NFSPROC_SETCLIENTID, nmp, NULL, 0, NULL);
771 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
772 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
773 *tl = txdr_unsigned(rev++);
774 (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen);
777 * set up the callback address
779 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
780 *tl = txdr_unsigned(NFS_CALLBCKPROG);
781 callblen = strlen(nfsv4_callbackaddr);
783 cp = nfscl_getmyip(nmp, &isinet6);
784 if (nfscl_enablecallb && nfs_numnfscbd > 0 &&
785 (callblen > 0 || cp != NULL)) {
786 port = htons(nfsv4_cbport);
787 cp2 = (u_int8_t *)&port;
790 strchr(nfsv4_callbackaddr, ':')) || isinet6) {
791 char ip6buf[INET6_ADDRSTRLEN], *ip6add;
793 (void) nfsm_strtom(nd, "tcp6", 4);
795 ip6_sprintf(ip6buf, (struct in6_addr *)cp);
798 ip6add = nfsv4_callbackaddr;
800 snprintf(addr, INET6_ADDRSTRLEN + 9, "%s.%d.%d",
801 ip6add, cp2[0], cp2[1]);
805 (void) nfsm_strtom(nd, "tcp", 3);
807 snprintf(addr, INET6_ADDRSTRLEN + 9,
808 "%d.%d.%d.%d.%d.%d", cp[0], cp[1],
809 cp[2], cp[3], cp2[0], cp2[1]);
811 snprintf(addr, INET6_ADDRSTRLEN + 9,
812 "%s.%d.%d", nfsv4_callbackaddr,
815 (void) nfsm_strtom(nd, addr, strlen(addr));
817 (void) nfsm_strtom(nd, "tcp", 3);
818 (void) nfsm_strtom(nd, "0.0.0.0.0.0", 11);
820 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
821 *tl = txdr_unsigned(clp->nfsc_cbident);
822 nd->nd_flag |= ND_USEGSSNAME;
823 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
824 NFS_PROG, NFS_VER4, NULL, 1, NULL);
827 if (nd->nd_repstat == 0) {
828 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
829 clp->nfsc_clientid.lval[0] = *tl++;
830 clp->nfsc_clientid.lval[1] = *tl++;
831 confirm.lval[0] = *tl++;
832 confirm.lval[1] = *tl;
833 mbuf_freem(nd->nd_mrep);
839 nfscl_reqstart(nd, NFSPROC_SETCLIENTIDCFRM, nmp, NULL, 0, NULL);
840 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
841 *tl++ = clp->nfsc_clientid.lval[0];
842 *tl++ = clp->nfsc_clientid.lval[1];
843 *tl++ = confirm.lval[0];
844 *tl = confirm.lval[1];
845 nd->nd_flag |= ND_USEGSSNAME;
846 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p,
847 cred, NFS_PROG, NFS_VER4, NULL, 1, NULL);
850 mbuf_freem(nd->nd_mrep);
852 if (nd->nd_repstat == 0) {
853 nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, nmp->nm_fh,
854 nmp->nm_fhsize, NULL);
855 NFSZERO_ATTRBIT(&attrbits);
856 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME);
857 (void) nfsrv_putattrbit(nd, &attrbits);
858 nd->nd_flag |= ND_USEGSSNAME;
859 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p,
860 cred, NFS_PROG, NFS_VER4, NULL, 1, NULL);
863 if (nd->nd_repstat == 0) {
864 error = nfsv4_loadattr(nd, NULL, NULL, NULL, NULL, 0, NULL,
865 NULL, NULL, NULL, NULL, 0, NULL, &lease, NULL, p, cred);
868 clp->nfsc_renew = NFSCL_RENEW(lease);
869 clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew;
870 clp->nfsc_clientidrev++;
871 if (clp->nfsc_clientidrev == 0)
872 clp->nfsc_clientidrev++;
876 error = nd->nd_repstat;
878 mbuf_freem(nd->nd_mrep);
886 nfsrpc_getattr(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
887 struct nfsvattr *nap, void *stuff)
889 struct nfsrv_descript nfsd, *nd = &nfsd;
891 nfsattrbit_t attrbits;
893 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
894 if (nd->nd_flag & ND_NFSV4) {
895 NFSGETATTR_ATTRBIT(&attrbits);
896 (void) nfsrv_putattrbit(nd, &attrbits);
898 error = nfscl_request(nd, vp, p, cred, stuff);
902 error = nfsm_loadattr(nd, nap);
904 error = nd->nd_repstat;
905 mbuf_freem(nd->nd_mrep);
910 * nfs getattr call with non-vnode arguemnts.
913 nfsrpc_getattrnovp(struct nfsmount *nmp, u_int8_t *fhp, int fhlen, int syscred,
914 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, u_int64_t *xidp)
916 struct nfsrv_descript nfsd, *nd = &nfsd;
917 int error, vers = NFS_VER2;
918 nfsattrbit_t attrbits;
920 nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, fhp, fhlen, NULL);
921 if (nd->nd_flag & ND_NFSV4) {
923 NFSGETATTR_ATTRBIT(&attrbits);
924 (void) nfsrv_putattrbit(nd, &attrbits);
925 } else if (nd->nd_flag & ND_NFSV3) {
929 nd->nd_flag |= ND_USEGSSNAME;
930 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
931 NFS_PROG, vers, NULL, 1, xidp);
935 error = nfsm_loadattr(nd, nap);
937 error = nd->nd_repstat;
938 mbuf_freem(nd->nd_mrep);
943 * Do an nfs setattr operation.
946 nfsrpc_setattr(vnode_t vp, struct vattr *vap, NFSACL_T *aclp,
947 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *rnap, int *attrflagp,
950 int error, expireret = 0, openerr, retrycnt;
951 u_int32_t clidrev = 0, mode;
952 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
954 nfsv4stateid_t stateid;
957 if (nmp->nm_clp != NULL)
958 clidrev = nmp->nm_clp->nfsc_clientidrev;
959 if (vap != NULL && NFSATTRISSET(u_quad_t, vap, va_size))
960 mode = NFSV4OPEN_ACCESSWRITE;
962 mode = NFSV4OPEN_ACCESSREAD;
967 if (NFSHASNFSV4(nmp)) {
968 nfhp = VTONFS(vp)->n_fhp;
969 error = nfscl_getstateid(vp, nfhp->nfh_fh,
970 nfhp->nfh_len, mode, cred, p, &stateid, &lckp);
971 if (error && vnode_vtype(vp) == VREG &&
972 (mode == NFSV4OPEN_ACCESSWRITE ||
973 nfstest_openallsetattr)) {
975 * No Open stateid, so try and open the file
978 if (mode == NFSV4OPEN_ACCESSWRITE)
979 openerr = nfsrpc_open(vp, FWRITE, cred,
982 openerr = nfsrpc_open(vp, FREAD, cred,
985 (void) nfscl_getstateid(vp,
986 nfhp->nfh_fh, nfhp->nfh_len,
987 mode, cred, p, &stateid, &lckp);
991 error = nfsrpc_setattrrpc(vp, vap, &stateid, cred, p,
992 rnap, attrflagp, stuff);
993 #ifdef NFS4_ACL_EXTATTR_NAME
995 error = nfsrpc_setaclrpc(vp, cred, p, aclp, &stateid,
1001 if (error == NFSERR_STALESTATEID)
1002 nfscl_initiate_recovery(nmp->nm_clp);
1004 nfscl_lockderef(lckp);
1006 (void) nfsrpc_close(vp, 0, p);
1007 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1008 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1009 error == NFSERR_OLDSTATEID) {
1010 (void) nfs_catnap(PZERO, error, "nfs_setattr");
1011 } else if ((error == NFSERR_EXPIRED ||
1012 error == NFSERR_BADSTATEID) && clidrev != 0) {
1013 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1016 } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1017 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1018 (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
1019 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1020 expireret == 0 && clidrev != 0 && retrycnt < 4));
1021 if (error && retrycnt >= 4)
1027 nfsrpc_setattrrpc(vnode_t vp, struct vattr *vap,
1028 nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p,
1029 struct nfsvattr *rnap, int *attrflagp, void *stuff)
1032 struct nfsrv_descript nfsd, *nd = &nfsd;
1034 nfsattrbit_t attrbits;
1037 NFSCL_REQSTART(nd, NFSPROC_SETATTR, vp);
1038 if (nd->nd_flag & ND_NFSV4)
1039 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
1040 vap->va_type = vnode_vtype(vp);
1041 nfscl_fillsattr(nd, vap, vp, NFSSATTR_FULL, 0);
1042 if (nd->nd_flag & ND_NFSV3) {
1043 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1045 } else if (nd->nd_flag & ND_NFSV4) {
1046 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1047 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1048 NFSGETATTR_ATTRBIT(&attrbits);
1049 (void) nfsrv_putattrbit(nd, &attrbits);
1051 error = nfscl_request(nd, vp, p, cred, stuff);
1054 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
1055 error = nfscl_wcc_data(nd, vp, rnap, attrflagp, NULL, stuff);
1056 if ((nd->nd_flag & ND_NFSV4) && !error)
1057 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1058 if (!(nd->nd_flag & ND_NFSV3) && !nd->nd_repstat && !error)
1059 error = nfscl_postop_attr(nd, rnap, attrflagp, stuff);
1060 mbuf_freem(nd->nd_mrep);
1061 if (nd->nd_repstat && !error)
1062 error = nd->nd_repstat;
1070 nfsrpc_lookup(vnode_t dvp, char *name, int len, struct ucred *cred,
1071 NFSPROC_T *p, struct nfsvattr *dnap, struct nfsvattr *nap,
1072 struct nfsfh **nfhpp, int *attrflagp, int *dattrflagp, void *stuff)
1075 struct nfsrv_descript nfsd, *nd = &nfsd;
1076 struct nfsmount *nmp;
1079 nfsattrbit_t attrbits;
1080 int error = 0, lookupp = 0;
1084 if (vnode_vtype(dvp) != VDIR)
1086 nmp = VFSTONFS(vnode_mount(dvp));
1087 if (len > NFS_MAXNAMLEN)
1088 return (ENAMETOOLONG);
1089 if (NFSHASNFSV4(nmp) && len == 1 &&
1092 * Just return the current dir's fh.
1095 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) +
1096 np->n_fhp->nfh_len, M_NFSFH, M_WAITOK);
1097 nfhp->nfh_len = np->n_fhp->nfh_len;
1098 NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len);
1102 if (NFSHASNFSV4(nmp) && len == 2 &&
1103 name[0] == '.' && name[1] == '.') {
1105 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, dvp);
1107 NFSCL_REQSTART(nd, NFSPROC_LOOKUP, dvp);
1108 (void) nfsm_strtom(nd, name, len);
1110 if (nd->nd_flag & ND_NFSV4) {
1111 NFSGETATTR_ATTRBIT(&attrbits);
1112 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1113 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
1114 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1115 (void) nfsrv_putattrbit(nd, &attrbits);
1117 error = nfscl_request(nd, dvp, p, cred, stuff);
1120 if (nd->nd_repstat) {
1122 * When an NFSv4 Lookupp returns ENOENT, it means that
1123 * the lookup is at the root of an fs, so return this dir.
1125 if (nd->nd_repstat == NFSERR_NOENT && lookupp) {
1127 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) +
1128 np->n_fhp->nfh_len, M_NFSFH, M_WAITOK);
1129 nfhp->nfh_len = np->n_fhp->nfh_len;
1130 NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len);
1132 mbuf_freem(nd->nd_mrep);
1135 if (nd->nd_flag & ND_NFSV3)
1136 error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff);
1139 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
1140 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1142 nd->nd_flag |= ND_NOMOREDATA;
1146 error = nfsm_getfh(nd, nfhpp);
1150 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
1151 if ((nd->nd_flag & ND_NFSV3) && !error)
1152 error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff);
1154 mbuf_freem(nd->nd_mrep);
1155 if (!error && nd->nd_repstat)
1156 error = nd->nd_repstat;
1161 * Do a readlink rpc.
1164 nfsrpc_readlink(vnode_t vp, struct uio *uiop, struct ucred *cred,
1165 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
1168 struct nfsrv_descript nfsd, *nd = &nfsd;
1169 struct nfsnode *np = VTONFS(vp);
1170 nfsattrbit_t attrbits;
1171 int error, len, cangetattr = 1;
1174 NFSCL_REQSTART(nd, NFSPROC_READLINK, vp);
1175 if (nd->nd_flag & ND_NFSV4) {
1177 * And do a Getattr op.
1179 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1180 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1181 NFSGETATTR_ATTRBIT(&attrbits);
1182 (void) nfsrv_putattrbit(nd, &attrbits);
1184 error = nfscl_request(nd, vp, p, cred, stuff);
1187 if (nd->nd_flag & ND_NFSV3)
1188 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
1189 if (!nd->nd_repstat && !error) {
1190 NFSM_STRSIZ(len, NFS_MAXPATHLEN);
1192 * This seems weird to me, but must have been added to
1193 * FreeBSD for some reason. The only thing I can think of
1194 * is that there was/is some server that replies with
1195 * more link data than it should?
1197 if (len == NFS_MAXPATHLEN) {
1199 if (np->n_size > 0 && np->n_size < NFS_MAXPATHLEN) {
1205 error = nfsm_mbufuio(nd, uiop, len);
1206 if ((nd->nd_flag & ND_NFSV4) && !error && cangetattr)
1207 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
1209 if (nd->nd_repstat && !error)
1210 error = nd->nd_repstat;
1212 mbuf_freem(nd->nd_mrep);
1220 nfsrpc_read(vnode_t vp, struct uio *uiop, struct ucred *cred,
1221 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
1223 int error, expireret = 0, retrycnt;
1224 u_int32_t clidrev = 0;
1225 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1226 struct nfsnode *np = VTONFS(vp);
1227 struct ucred *newcred;
1228 struct nfsfh *nfhp = NULL;
1229 nfsv4stateid_t stateid;
1232 if (nmp->nm_clp != NULL)
1233 clidrev = nmp->nm_clp->nfsc_clientidrev;
1235 if (NFSHASNFSV4(nmp)) {
1238 newcred = NFSNEWCRED(cred);
1243 if (NFSHASNFSV4(nmp))
1244 (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
1245 NFSV4OPEN_ACCESSREAD, newcred, p, &stateid, &lckp);
1246 error = nfsrpc_readrpc(vp, uiop, newcred, &stateid, p, nap,
1248 if (error == NFSERR_STALESTATEID)
1249 nfscl_initiate_recovery(nmp->nm_clp);
1251 nfscl_lockderef(lckp);
1252 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1253 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1254 error == NFSERR_OLDSTATEID) {
1255 (void) nfs_catnap(PZERO, error, "nfs_read");
1256 } else if ((error == NFSERR_EXPIRED ||
1257 error == NFSERR_BADSTATEID) && clidrev != 0) {
1258 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1261 } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1262 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1263 (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
1264 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1265 expireret == 0 && clidrev != 0 && retrycnt < 4));
1266 if (error && retrycnt >= 4)
1268 if (NFSHASNFSV4(nmp) && p == NULL)
1269 NFSFREECRED(newcred);
1274 * The actual read RPC.
1277 nfsrpc_readrpc(vnode_t vp, struct uio *uiop, struct ucred *cred,
1278 nfsv4stateid_t *stateidp, NFSPROC_T *p, struct nfsvattr *nap,
1279 int *attrflagp, void *stuff)
1282 int error = 0, len, retlen, tsiz, eof = 0;
1283 struct nfsrv_descript nfsd;
1284 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1285 struct nfsrv_descript *nd = &nfsd;
1288 tsiz = uio_uio_resid(uiop);
1289 if (uiop->uio_offset + tsiz > 0xffffffff &&
1290 !NFSHASNFSV3OR4(nmp))
1295 len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
1296 NFSCL_REQSTART(nd, NFSPROC_READ, vp);
1297 if (nd->nd_flag & ND_NFSV4)
1298 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
1299 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED * 3);
1300 if (nd->nd_flag & ND_NFSV2) {
1301 *tl++ = txdr_unsigned(uiop->uio_offset);
1302 *tl++ = txdr_unsigned(len);
1305 txdr_hyper(uiop->uio_offset, tl);
1306 *(tl + 2) = txdr_unsigned(len);
1309 * Since I can't do a Getattr for NFSv4 for Write, there
1310 * doesn't seem any point in doing one here, either.
1311 * (See the comment in nfsrpc_writerpc() for more info.)
1313 error = nfscl_request(nd, vp, p, cred, stuff);
1316 if (nd->nd_flag & ND_NFSV3) {
1317 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
1318 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
1319 error = nfsm_loadattr(nd, nap);
1323 if (nd->nd_repstat || error) {
1325 error = nd->nd_repstat;
1328 if (nd->nd_flag & ND_NFSV3) {
1329 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1330 eof = fxdr_unsigned(int, *(tl + 1));
1331 } else if (nd->nd_flag & ND_NFSV4) {
1332 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1333 eof = fxdr_unsigned(int, *tl);
1335 NFSM_STRSIZ(retlen, nmp->nm_rsize);
1336 error = nfsm_mbufuio(nd, uiop, retlen);
1339 mbuf_freem(nd->nd_mrep);
1342 if (!(nd->nd_flag & ND_NFSV2)) {
1343 if (eof || retlen == 0)
1345 } else if (retlen < len)
1350 if (nd->nd_mrep != NULL)
1351 mbuf_freem(nd->nd_mrep);
1356 * nfs write operation
1357 * When called_from_strategy != 0, it should return EIO for an error that
1358 * indicates recovery is in progress, so that the buffer will be left
1359 * dirty and be written back to the server later. If it loops around,
1360 * the recovery thread could get stuck waiting for the buffer and recovery
1361 * will then deadlock.
1364 nfsrpc_write(vnode_t vp, struct uio *uiop, int *iomode, u_char *verfp,
1365 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
1366 void *stuff, int called_from_strategy)
1368 int error, expireret = 0, retrycnt, nostateid;
1369 u_int32_t clidrev = 0;
1370 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1371 struct nfsnode *np = VTONFS(vp);
1372 struct ucred *newcred;
1373 struct nfsfh *nfhp = NULL;
1374 nfsv4stateid_t stateid;
1377 if (nmp->nm_clp != NULL)
1378 clidrev = nmp->nm_clp->nfsc_clientidrev;
1380 if (NFSHASNFSV4(nmp)) {
1382 newcred = NFSNEWCRED(cred);
1389 if (NFSHASNFSV4(nmp)) {
1390 (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
1391 NFSV4OPEN_ACCESSWRITE, newcred, p, &stateid, &lckp);
1392 if (stateid.other[0] == 0 && stateid.other[1] == 0 &&
1393 stateid.other[2] == 0) {
1395 printf("stateid0 in write\n");
1400 * If there is no stateid for NFSv4, it means this is an
1401 * extraneous write after close. Basically a poorly
1402 * implemented buffer cache. Just don't do the write.
1407 error = nfsrpc_writerpc(vp, uiop, iomode, verfp,
1408 newcred, &stateid, p, nap, attrflagp, stuff);
1409 if (error == NFSERR_STALESTATEID)
1410 nfscl_initiate_recovery(nmp->nm_clp);
1412 nfscl_lockderef(lckp);
1413 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1414 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1415 error == NFSERR_OLDSTATEID) {
1416 (void) nfs_catnap(PZERO, error, "nfs_write");
1417 } else if ((error == NFSERR_EXPIRED ||
1418 error == NFSERR_BADSTATEID) && clidrev != 0) {
1419 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1422 } while (error == NFSERR_GRACE || error == NFSERR_DELAY ||
1423 ((error == NFSERR_STALESTATEID ||
1424 error == NFSERR_STALEDONTRECOVER) && called_from_strategy == 0) ||
1425 (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
1426 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1427 expireret == 0 && clidrev != 0 && retrycnt < 4));
1428 if (error != 0 && (retrycnt >= 4 ||
1429 ((error == NFSERR_STALESTATEID ||
1430 error == NFSERR_STALEDONTRECOVER) && called_from_strategy != 0)))
1432 if (NFSHASNFSV4(nmp) && p == NULL)
1433 NFSFREECRED(newcred);
1438 * The actual write RPC.
1441 nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode,
1442 u_char *verfp, struct ucred *cred, nfsv4stateid_t *stateidp,
1443 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
1446 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1447 struct nfsnode *np = VTONFS(vp);
1448 int error = 0, len, tsiz, rlen, commit, committed = NFSWRITE_FILESYNC;
1449 int wccflag = 0, wsize;
1451 struct nfsrv_descript nfsd;
1452 struct nfsrv_descript *nd = &nfsd;
1453 nfsattrbit_t attrbits;
1455 KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1"));
1457 tsiz = uio_uio_resid(uiop);
1459 if (uiop->uio_offset + tsiz > 0xffffffff &&
1460 !NFSHASNFSV3OR4(nmp)) {
1464 wsize = nmp->nm_wsize;
1466 nd->nd_mrep = NULL; /* NFSv2 sometimes does a write with */
1467 nd->nd_repstat = 0; /* uio_resid == 0, so the while is not done */
1469 nmp = VFSTONFS(vnode_mount(vp));
1475 len = (tsiz > wsize) ? wsize : tsiz;
1476 NFSCL_REQSTART(nd, NFSPROC_WRITE, vp);
1477 if (nd->nd_flag & ND_NFSV4) {
1478 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
1479 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+2*NFSX_UNSIGNED);
1480 txdr_hyper(uiop->uio_offset, tl);
1482 *tl++ = txdr_unsigned(*iomode);
1483 *tl = txdr_unsigned(len);
1484 } else if (nd->nd_flag & ND_NFSV3) {
1485 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+3*NFSX_UNSIGNED);
1486 txdr_hyper(uiop->uio_offset, tl);
1488 *tl++ = txdr_unsigned(len);
1489 *tl++ = txdr_unsigned(*iomode);
1490 *tl = txdr_unsigned(len);
1494 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1496 * Not sure why someone changed this, since the
1497 * RFC clearly states that "beginoffset" and
1498 * "totalcount" are ignored, but it wouldn't
1499 * surprise me if there's a busted server out there.
1501 /* Set both "begin" and "current" to non-garbage. */
1502 x = txdr_unsigned((u_int32_t)uiop->uio_offset);
1503 *tl++ = x; /* "begin offset" */
1504 *tl++ = x; /* "current offset" */
1505 x = txdr_unsigned(len);
1506 *tl++ = x; /* total to this offset */
1507 *tl = x; /* size of this write */
1510 nfsm_uiombuf(nd, uiop, len);
1512 * Although it is tempting to do a normal Getattr Op in the
1513 * NFSv4 compound, the result can be a nearly hung client
1514 * system if the Getattr asks for Owner and/or OwnerGroup.
1515 * It occurs when the client can't map either the Owner or
1516 * Owner_group name in the Getattr reply to a uid/gid. When
1517 * there is a cache miss, the kernel does an upcall to the
1518 * nfsuserd. Then, it can try and read the local /etc/passwd
1519 * or /etc/group file. It can then block in getnewbuf(),
1520 * waiting for dirty writes to be pushed to the NFS server.
1521 * The only reason this doesn't result in a complete
1522 * deadlock, is that the upcall times out and allows
1523 * the write to complete. However, progress is so slow
1524 * that it might just as well be deadlocked.
1525 * So, we just get the attributes that change with each
1527 * nb: nfscl_loadattrcache() needs to be told that these
1528 * partial attributes from a write rpc are being
1529 * passed in, via a argument flag.
1531 if (nd->nd_flag & ND_NFSV4) {
1532 NFSWRITEGETATTR_ATTRBIT(&attrbits);
1533 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1534 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1535 (void) nfsrv_putattrbit(nd, &attrbits);
1537 error = nfscl_request(nd, vp, p, cred, stuff);
1540 if (nd->nd_repstat) {
1542 * In case the rpc gets retried, roll
1543 * the uio fileds changed by nfsm_uiombuf()
1546 uiop->uio_offset -= len;
1547 uio_uio_resid_add(uiop, len);
1548 uio_iov_base_add(uiop, -len);
1549 uio_iov_len_add(uiop, len);
1551 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1552 error = nfscl_wcc_data(nd, vp, nap, attrflagp,
1557 if (!nd->nd_repstat) {
1558 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1559 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED
1561 rlen = fxdr_unsigned(int, *tl++);
1565 } else if (rlen < len) {
1566 backup = len - rlen;
1567 uio_iov_base_add(uiop, -(backup));
1568 uio_iov_len_add(uiop, backup);
1569 uiop->uio_offset -= backup;
1570 uio_uio_resid_add(uiop, backup);
1573 commit = fxdr_unsigned(int, *tl++);
1576 * Return the lowest committment level
1577 * obtained by any of the RPCs.
1579 if (committed == NFSWRITE_FILESYNC)
1581 else if (committed == NFSWRITE_DATASYNC &&
1582 commit == NFSWRITE_UNSTABLE)
1585 NFSBCOPY((caddr_t)tl, verfp, NFSX_VERF);
1587 if (!NFSHASWRITEVERF(nmp)) {
1588 NFSBCOPY((caddr_t)tl,
1589 (caddr_t)&nmp->nm_verf[0],
1591 NFSSETWRITEVERF(nmp);
1595 if (nd->nd_flag & ND_NFSV4)
1596 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1597 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV4)) {
1598 error = nfsm_loadattr(nd, nap);
1600 *attrflagp = NFS_LATTR_NOSHRINK;
1603 error = nd->nd_repstat;
1607 NFSWRITERPC_SETTIME(wccflag, np, (nd->nd_flag & ND_NFSV4));
1608 mbuf_freem(nd->nd_mrep);
1613 if (nd->nd_mrep != NULL)
1614 mbuf_freem(nd->nd_mrep);
1615 *iomode = committed;
1616 if (nd->nd_repstat && !error)
1617 error = nd->nd_repstat;
1623 * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the
1624 * mode set to specify the file type and the size field for rdev.
1627 nfsrpc_mknod(vnode_t dvp, char *name, int namelen, struct vattr *vap,
1628 u_int32_t rdev, enum vtype vtyp, struct ucred *cred, NFSPROC_T *p,
1629 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
1630 int *attrflagp, int *dattrflagp, void *dstuff)
1634 struct nfsrv_descript nfsd, *nd = &nfsd;
1635 nfsattrbit_t attrbits;
1640 if (namelen > NFS_MAXNAMLEN)
1641 return (ENAMETOOLONG);
1642 NFSCL_REQSTART(nd, NFSPROC_MKNOD, dvp);
1643 if (nd->nd_flag & ND_NFSV4) {
1644 if (vtyp == VBLK || vtyp == VCHR) {
1645 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1646 *tl++ = vtonfsv34_type(vtyp);
1647 *tl++ = txdr_unsigned(NFSMAJOR(rdev));
1648 *tl = txdr_unsigned(NFSMINOR(rdev));
1650 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1651 *tl = vtonfsv34_type(vtyp);
1654 (void) nfsm_strtom(nd, name, namelen);
1655 if (nd->nd_flag & ND_NFSV3) {
1656 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1657 *tl = vtonfsv34_type(vtyp);
1659 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
1660 nfscl_fillsattr(nd, vap, dvp, 0, 0);
1661 if ((nd->nd_flag & ND_NFSV3) &&
1662 (vtyp == VCHR || vtyp == VBLK)) {
1663 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1664 *tl++ = txdr_unsigned(NFSMAJOR(rdev));
1665 *tl = txdr_unsigned(NFSMINOR(rdev));
1667 if (nd->nd_flag & ND_NFSV4) {
1668 NFSGETATTR_ATTRBIT(&attrbits);
1669 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1670 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
1671 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1672 (void) nfsrv_putattrbit(nd, &attrbits);
1674 if (nd->nd_flag & ND_NFSV2)
1675 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZERDEV, rdev);
1676 error = nfscl_request(nd, dvp, p, cred, dstuff);
1679 if (nd->nd_flag & ND_NFSV4)
1680 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
1681 if (!nd->nd_repstat) {
1682 if (nd->nd_flag & ND_NFSV4) {
1683 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1684 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1688 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
1692 if (nd->nd_flag & ND_NFSV3)
1693 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
1694 if (!error && nd->nd_repstat)
1695 error = nd->nd_repstat;
1697 mbuf_freem(nd->nd_mrep);
1702 * nfs file create call
1703 * Mostly just call the approriate routine. (I separated out v4, so that
1704 * error recovery wouldn't be as difficult.)
1707 nfsrpc_create(vnode_t dvp, char *name, int namelen, struct vattr *vap,
1708 nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p,
1709 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
1710 int *attrflagp, int *dattrflagp, void *dstuff)
1712 int error = 0, newone, expireret = 0, retrycnt, unlocked;
1713 struct nfsclowner *owp;
1714 struct nfscldeleg *dp;
1715 struct nfsmount *nmp = VFSTONFS(vnode_mount(dvp));
1718 if (NFSHASNFSV4(nmp)) {
1722 error = nfscl_open(dvp, NULL, 0, (NFSV4OPEN_ACCESSWRITE |
1723 NFSV4OPEN_ACCESSREAD), 0, cred, p, &owp, NULL, &newone,
1727 if (nmp->nm_clp != NULL)
1728 clidrev = nmp->nm_clp->nfsc_clientidrev;
1731 error = nfsrpc_createv4(dvp, name, namelen, vap, cverf, fmode,
1732 owp, &dp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp,
1735 (void) nfscl_deleg(nmp->nm_mountp, owp->nfsow_clp,
1736 (*nfhpp)->nfh_fh, (*nfhpp)->nfh_len, cred, p, &dp);
1737 nfscl_ownerrelease(owp, error, newone, unlocked);
1738 if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
1739 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY) {
1740 (void) nfs_catnap(PZERO, error, "nfs_open");
1741 } else if ((error == NFSERR_EXPIRED ||
1742 error == NFSERR_BADSTATEID) && clidrev != 0) {
1743 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1746 } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
1747 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1748 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1749 expireret == 0 && clidrev != 0 && retrycnt < 4));
1750 if (error && retrycnt >= 4)
1753 error = nfsrpc_createv23(dvp, name, namelen, vap, cverf,
1754 fmode, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp,
1761 * The create rpc for v2 and 3.
1764 nfsrpc_createv23(vnode_t dvp, char *name, int namelen, struct vattr *vap,
1765 nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p,
1766 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
1767 int *attrflagp, int *dattrflagp, void *dstuff)
1771 struct nfsrv_descript nfsd, *nd = &nfsd;
1776 if (namelen > NFS_MAXNAMLEN)
1777 return (ENAMETOOLONG);
1778 NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp);
1779 (void) nfsm_strtom(nd, name, namelen);
1780 if (nd->nd_flag & ND_NFSV3) {
1781 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1782 if (fmode & O_EXCL) {
1783 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE);
1784 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
1785 *tl++ = cverf.lval[0];
1786 *tl = cverf.lval[1];
1788 *tl = txdr_unsigned(NFSCREATE_UNCHECKED);
1789 nfscl_fillsattr(nd, vap, dvp, 0, 0);
1792 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZE0, 0);
1794 error = nfscl_request(nd, dvp, p, cred, dstuff);
1797 if (nd->nd_repstat == 0) {
1798 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
1802 if (nd->nd_flag & ND_NFSV3)
1803 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
1804 if (nd->nd_repstat != 0 && error == 0)
1805 error = nd->nd_repstat;
1807 mbuf_freem(nd->nd_mrep);
1812 nfsrpc_createv4(vnode_t dvp, char *name, int namelen, struct vattr *vap,
1813 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp,
1814 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
1815 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
1816 int *dattrflagp, void *dstuff, int *unlockedp)
1819 int error = 0, deleg, newone, ret, acesize, limitby;
1820 struct nfsrv_descript nfsd, *nd = &nfsd;
1821 struct nfsclopen *op;
1822 struct nfscldeleg *dp = NULL;
1825 nfsattrbit_t attrbits;
1826 nfsv4stateid_t stateid;
1834 if (namelen > NFS_MAXNAMLEN)
1835 return (ENAMETOOLONG);
1836 NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp);
1838 * For V4, this is actually an Open op.
1840 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1841 *tl++ = txdr_unsigned(owp->nfsow_seqid);
1842 *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
1843 NFSV4OPEN_ACCESSREAD);
1844 *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE);
1845 *tl++ = owp->nfsow_clp->nfsc_clientid.lval[0];
1846 *tl = owp->nfsow_clp->nfsc_clientid.lval[1];
1847 (void) nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN);
1848 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1849 *tl++ = txdr_unsigned(NFSV4OPEN_CREATE);
1850 if (fmode & O_EXCL) {
1851 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE);
1852 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
1853 *tl++ = cverf.lval[0];
1854 *tl = cverf.lval[1];
1856 *tl = txdr_unsigned(NFSCREATE_UNCHECKED);
1857 nfscl_fillsattr(nd, vap, dvp, 0, 0);
1859 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1860 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
1861 (void) nfsm_strtom(nd, name, namelen);
1862 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1863 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
1864 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1865 NFSGETATTR_ATTRBIT(&attrbits);
1866 (void) nfsrv_putattrbit(nd, &attrbits);
1867 error = nfscl_request(nd, dvp, p, cred, dstuff);
1870 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
1873 NFSCL_INCRSEQID(owp->nfsow_seqid, nd);
1874 if (nd->nd_repstat == 0) {
1875 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
1877 stateid.seqid = *tl++;
1878 stateid.other[0] = *tl++;
1879 stateid.other[1] = *tl++;
1880 stateid.other[2] = *tl;
1881 rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
1882 (void) nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1883 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1884 deleg = fxdr_unsigned(int, *tl);
1885 if (deleg == NFSV4OPEN_DELEGATEREAD ||
1886 deleg == NFSV4OPEN_DELEGATEWRITE) {
1887 if (!(owp->nfsow_clp->nfsc_flags &
1888 NFSCLFLAGS_FIRSTDELEG))
1889 owp->nfsow_clp->nfsc_flags |=
1890 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
1891 MALLOC(dp, struct nfscldeleg *,
1892 sizeof (struct nfscldeleg) + NFSX_V4FHMAX,
1893 M_NFSCLDELEG, M_WAITOK);
1894 LIST_INIT(&dp->nfsdl_owner);
1895 LIST_INIT(&dp->nfsdl_lock);
1896 dp->nfsdl_clp = owp->nfsow_clp;
1897 newnfs_copyincred(cred, &dp->nfsdl_cred);
1898 nfscl_lockinit(&dp->nfsdl_rwlock);
1899 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
1901 dp->nfsdl_stateid.seqid = *tl++;
1902 dp->nfsdl_stateid.other[0] = *tl++;
1903 dp->nfsdl_stateid.other[1] = *tl++;
1904 dp->nfsdl_stateid.other[2] = *tl++;
1905 ret = fxdr_unsigned(int, *tl);
1906 if (deleg == NFSV4OPEN_DELEGATEWRITE) {
1907 dp->nfsdl_flags = NFSCLDL_WRITE;
1909 * Indicates how much the file can grow.
1911 NFSM_DISSECT(tl, u_int32_t *,
1913 limitby = fxdr_unsigned(int, *tl++);
1915 case NFSV4OPEN_LIMITSIZE:
1916 dp->nfsdl_sizelimit = fxdr_hyper(tl);
1918 case NFSV4OPEN_LIMITBLOCKS:
1919 dp->nfsdl_sizelimit =
1920 fxdr_unsigned(u_int64_t, *tl++);
1921 dp->nfsdl_sizelimit *=
1922 fxdr_unsigned(u_int64_t, *tl);
1925 error = NFSERR_BADXDR;
1929 dp->nfsdl_flags = NFSCLDL_READ;
1932 dp->nfsdl_flags |= NFSCLDL_RECALL;
1933 error = nfsrv_dissectace(nd, &dp->nfsdl_ace, &ret,
1937 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
1938 error = NFSERR_BADXDR;
1941 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
1944 if (dp != NULL && *attrflagp) {
1945 dp->nfsdl_change = nnap->na_filerev;
1946 dp->nfsdl_modtime = nnap->na_mtime;
1947 dp->nfsdl_flags |= NFSCLDL_MODTIMESET;
1950 * We can now complete the Open state.
1954 dp->nfsdl_fhlen = nfhp->nfh_len;
1955 NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, nfhp->nfh_len);
1958 * Get an Open structure that will be
1959 * attached to the OpenOwner, acquired already.
1961 error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len,
1962 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0,
1963 cred, p, NULL, &op, &newone, NULL, 0);
1966 op->nfso_stateid = stateid;
1967 newnfs_copyincred(cred, &op->nfso_cred);
1968 if ((rflags & NFSV4OPEN_RESULTCONFIRM)) {
1970 ret = nfsrpc_openconfirm(dvp, nfhp->nfh_fh,
1971 nfhp->nfh_len, op, cred, p);
1972 if (ret == NFSERR_DELAY)
1973 (void) nfs_catnap(PZERO, ret, "nfs_create");
1974 } while (ret == NFSERR_DELAY);
1979 * If the server is handing out delegations, but we didn't
1980 * get one because an OpenConfirm was required, try the
1981 * Open again, to get a delegation. This is a harmless no-op,
1982 * from a server's point of view.
1984 if ((rflags & NFSV4OPEN_RESULTCONFIRM) &&
1985 (owp->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) &&
1986 !error && dp == NULL) {
1989 ret = nfsrpc_openrpc(VFSTONFS(vnode_mount(dvp)), dvp,
1990 np->n_fhp->nfh_fh, np->n_fhp->nfh_len,
1991 nfhp->nfh_fh, nfhp->nfh_len,
1992 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), op,
1993 name, namelen, &dp, 0, 0x0, cred, p, 0, 1);
1994 if (ret == NFSERR_DELAY)
1995 (void) nfs_catnap(PZERO, ret, "nfs_crt2");
1996 } while (ret == NFSERR_DELAY);
1999 FREE((caddr_t)dp, M_NFSCLDELEG);
2000 if (ret == NFSERR_STALECLIENTID ||
2001 ret == NFSERR_STALEDONTRECOVER)
2005 nfscl_openrelease(op, error, newone);
2008 if (nd->nd_repstat != 0 && error == 0)
2009 error = nd->nd_repstat;
2010 if (error == NFSERR_STALECLIENTID)
2011 nfscl_initiate_recovery(owp->nfsow_clp);
2015 else if (dp != NULL)
2016 FREE((caddr_t)dp, M_NFSCLDELEG);
2017 mbuf_freem(nd->nd_mrep);
2025 nfsrpc_remove(vnode_t dvp, char *name, int namelen, vnode_t vp,
2026 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp,
2030 struct nfsrv_descript nfsd, *nd = &nfsd;
2032 struct nfsmount *nmp;
2033 nfsv4stateid_t dstateid;
2034 int error, ret = 0, i;
2037 if (namelen > NFS_MAXNAMLEN)
2038 return (ENAMETOOLONG);
2039 nmp = VFSTONFS(vnode_mount(dvp));
2041 if (NFSHASNFSV4(nmp) && ret == 0) {
2042 ret = nfscl_removedeleg(vp, p, &dstateid);
2044 NFSCL_REQSTART(nd, NFSPROC_RETDELEGREMOVE, vp);
2045 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID +
2047 *tl++ = dstateid.seqid;
2048 *tl++ = dstateid.other[0];
2049 *tl++ = dstateid.other[1];
2050 *tl++ = dstateid.other[2];
2051 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2053 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
2054 np->n_fhp->nfh_len, 0);
2055 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2056 *tl = txdr_unsigned(NFSV4OP_REMOVE);
2062 NFSCL_REQSTART(nd, NFSPROC_REMOVE, dvp);
2063 (void) nfsm_strtom(nd, name, namelen);
2064 error = nfscl_request(nd, dvp, p, cred, dstuff);
2067 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
2068 /* For NFSv4, parse out any Delereturn replies. */
2069 if (ret > 0 && nd->nd_repstat != 0 &&
2070 (nd->nd_flag & ND_NOMOREDATA)) {
2072 * If the Delegreturn failed, try again without
2073 * it. The server will Recall, as required.
2075 mbuf_freem(nd->nd_mrep);
2078 for (i = 0; i < (ret * 2); i++) {
2079 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
2081 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2083 nd->nd_flag |= ND_NOMOREDATA;
2086 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2088 if (nd->nd_repstat && !error)
2089 error = nd->nd_repstat;
2091 mbuf_freem(nd->nd_mrep);
2096 * Do an nfs rename rpc.
2099 nfsrpc_rename(vnode_t fdvp, vnode_t fvp, char *fnameptr, int fnamelen,
2100 vnode_t tdvp, vnode_t tvp, char *tnameptr, int tnamelen, struct ucred *cred,
2101 NFSPROC_T *p, struct nfsvattr *fnap, struct nfsvattr *tnap,
2102 int *fattrflagp, int *tattrflagp, void *fstuff, void *tstuff)
2105 struct nfsrv_descript nfsd, *nd = &nfsd;
2106 struct nfsmount *nmp;
2108 nfsattrbit_t attrbits;
2109 nfsv4stateid_t fdstateid, tdstateid;
2110 int error = 0, ret = 0, gottd = 0, gotfd = 0, i;
2114 nmp = VFSTONFS(vnode_mount(fdvp));
2115 if (fnamelen > NFS_MAXNAMLEN || tnamelen > NFS_MAXNAMLEN)
2116 return (ENAMETOOLONG);
2118 if (NFSHASNFSV4(nmp) && ret == 0) {
2119 ret = nfscl_renamedeleg(fvp, &fdstateid, &gotfd, tvp,
2120 &tdstateid, &gottd, p);
2121 if (gotfd && gottd) {
2122 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME2, fvp);
2124 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, fvp);
2126 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, tvp);
2129 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2130 *tl++ = fdstateid.seqid;
2131 *tl++ = fdstateid.other[0];
2132 *tl++ = fdstateid.other[1];
2133 *tl = fdstateid.other[2];
2135 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2136 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2138 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
2139 np->n_fhp->nfh_len, 0);
2140 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2141 *tl = txdr_unsigned(NFSV4OP_DELEGRETURN);
2145 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2146 *tl++ = tdstateid.seqid;
2147 *tl++ = tdstateid.other[0];
2148 *tl++ = tdstateid.other[1];
2149 *tl = tdstateid.other[2];
2152 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2153 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2155 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
2156 np->n_fhp->nfh_len, 0);
2157 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2158 *tl = txdr_unsigned(NFSV4OP_SAVEFH);
2164 NFSCL_REQSTART(nd, NFSPROC_RENAME, fdvp);
2165 if (nd->nd_flag & ND_NFSV4) {
2166 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2167 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2168 NFSWCCATTR_ATTRBIT(&attrbits);
2169 (void) nfsrv_putattrbit(nd, &attrbits);
2170 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2171 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2172 (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh,
2173 VTONFS(tdvp)->n_fhp->nfh_len, 0);
2174 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2175 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2176 (void) nfsrv_putattrbit(nd, &attrbits);
2177 nd->nd_flag |= ND_V4WCCATTR;
2178 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2179 *tl = txdr_unsigned(NFSV4OP_RENAME);
2181 (void) nfsm_strtom(nd, fnameptr, fnamelen);
2182 if (!(nd->nd_flag & ND_NFSV4))
2183 (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh,
2184 VTONFS(tdvp)->n_fhp->nfh_len, 0);
2185 (void) nfsm_strtom(nd, tnameptr, tnamelen);
2186 error = nfscl_request(nd, fdvp, p, cred, fstuff);
2189 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
2190 /* For NFSv4, parse out any Delereturn replies. */
2191 if (ret > 0 && nd->nd_repstat != 0 &&
2192 (nd->nd_flag & ND_NOMOREDATA)) {
2194 * If the Delegreturn failed, try again without
2195 * it. The server will Recall, as required.
2197 mbuf_freem(nd->nd_mrep);
2200 for (i = 0; i < (ret * 2); i++) {
2201 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
2203 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2205 if (i == 0 && ret > 1) {
2207 * If the Delegreturn failed, try again
2208 * without it. The server will Recall, as
2210 * If ret > 1, the first iteration of this
2211 * loop is the second DelegReturn result.
2213 mbuf_freem(nd->nd_mrep);
2216 nd->nd_flag |= ND_NOMOREDATA;
2221 /* Now, the first wcc attribute reply. */
2222 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
2223 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2225 nd->nd_flag |= ND_NOMOREDATA;
2227 error = nfscl_wcc_data(nd, fdvp, fnap, fattrflagp, NULL,
2229 /* and the second wcc attribute reply. */
2230 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 &&
2232 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2234 nd->nd_flag |= ND_NOMOREDATA;
2237 error = nfscl_wcc_data(nd, tdvp, tnap, tattrflagp,
2240 if (nd->nd_repstat && !error)
2241 error = nd->nd_repstat;
2243 mbuf_freem(nd->nd_mrep);
2248 * nfs hard link create rpc
2251 nfsrpc_link(vnode_t dvp, vnode_t vp, char *name, int namelen,
2252 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
2253 struct nfsvattr *nap, int *attrflagp, int *dattrflagp, void *dstuff)
2256 struct nfsrv_descript nfsd, *nd = &nfsd;
2257 nfsattrbit_t attrbits;
2262 if (namelen > NFS_MAXNAMLEN)
2263 return (ENAMETOOLONG);
2264 NFSCL_REQSTART(nd, NFSPROC_LINK, vp);
2265 if (nd->nd_flag & ND_NFSV4) {
2266 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2267 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2269 (void) nfsm_fhtom(nd, VTONFS(dvp)->n_fhp->nfh_fh,
2270 VTONFS(dvp)->n_fhp->nfh_len, 0);
2271 if (nd->nd_flag & ND_NFSV4) {
2272 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2273 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2274 NFSWCCATTR_ATTRBIT(&attrbits);
2275 (void) nfsrv_putattrbit(nd, &attrbits);
2276 nd->nd_flag |= ND_V4WCCATTR;
2277 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2278 *tl = txdr_unsigned(NFSV4OP_LINK);
2280 (void) nfsm_strtom(nd, name, namelen);
2281 error = nfscl_request(nd, vp, p, cred, dstuff);
2284 if (nd->nd_flag & ND_NFSV3) {
2285 error = nfscl_postop_attr(nd, nap, attrflagp, dstuff);
2287 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp,
2289 } else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
2291 * First, parse out the PutFH and Getattr result.
2293 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2295 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2297 nd->nd_flag |= ND_NOMOREDATA;
2299 * Get the pre-op attributes.
2301 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2303 if (nd->nd_repstat && !error)
2304 error = nd->nd_repstat;
2306 mbuf_freem(nd->nd_mrep);
2311 * nfs symbolic link create rpc
2314 nfsrpc_symlink(vnode_t dvp, char *name, int namelen, char *target,
2315 struct vattr *vap, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
2316 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
2317 int *dattrflagp, void *dstuff)
2320 struct nfsrv_descript nfsd, *nd = &nfsd;
2321 struct nfsmount *nmp;
2322 int slen, error = 0;
2327 nmp = VFSTONFS(vnode_mount(dvp));
2328 slen = strlen(target);
2329 if (slen > NFS_MAXPATHLEN || namelen > NFS_MAXNAMLEN)
2330 return (ENAMETOOLONG);
2331 NFSCL_REQSTART(nd, NFSPROC_SYMLINK, dvp);
2332 if (nd->nd_flag & ND_NFSV4) {
2333 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2334 *tl = txdr_unsigned(NFLNK);
2335 (void) nfsm_strtom(nd, target, slen);
2337 (void) nfsm_strtom(nd, name, namelen);
2338 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
2339 nfscl_fillsattr(nd, vap, dvp, 0, 0);
2340 if (!(nd->nd_flag & ND_NFSV4))
2341 (void) nfsm_strtom(nd, target, slen);
2342 if (nd->nd_flag & ND_NFSV2)
2343 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0);
2344 error = nfscl_request(nd, dvp, p, cred, dstuff);
2347 if (nd->nd_flag & ND_NFSV4)
2348 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2349 if ((nd->nd_flag & ND_NFSV3) && !error) {
2350 if (!nd->nd_repstat)
2351 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
2353 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp,
2356 if (nd->nd_repstat && !error)
2357 error = nd->nd_repstat;
2358 mbuf_freem(nd->nd_mrep);
2360 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
2362 if (error == EEXIST)
2371 nfsrpc_mkdir(vnode_t dvp, char *name, int namelen, struct vattr *vap,
2372 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
2373 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
2374 int *dattrflagp, void *dstuff)
2377 struct nfsrv_descript nfsd, *nd = &nfsd;
2378 nfsattrbit_t attrbits;
2384 if (namelen > NFS_MAXNAMLEN)
2385 return (ENAMETOOLONG);
2386 NFSCL_REQSTART(nd, NFSPROC_MKDIR, dvp);
2387 if (nd->nd_flag & ND_NFSV4) {
2388 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2389 *tl = txdr_unsigned(NFDIR);
2391 (void) nfsm_strtom(nd, name, namelen);
2392 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0);
2393 if (nd->nd_flag & ND_NFSV4) {
2394 NFSGETATTR_ATTRBIT(&attrbits);
2395 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2396 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
2397 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2398 (void) nfsrv_putattrbit(nd, &attrbits);
2400 error = nfscl_request(nd, dvp, p, cred, dstuff);
2403 if (nd->nd_flag & ND_NFSV4)
2404 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2405 if (!nd->nd_repstat && !error) {
2406 if (nd->nd_flag & ND_NFSV4) {
2407 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2408 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
2411 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
2413 if ((nd->nd_flag & ND_NFSV3) && !error)
2414 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2415 if (nd->nd_repstat && !error)
2416 error = nd->nd_repstat;
2418 mbuf_freem(nd->nd_mrep);
2420 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry.
2422 if (error == EEXIST)
2428 * nfs remove directory call
2431 nfsrpc_rmdir(vnode_t dvp, char *name, int namelen, struct ucred *cred,
2432 NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp, void *dstuff)
2434 struct nfsrv_descript nfsd, *nd = &nfsd;
2438 if (namelen > NFS_MAXNAMLEN)
2439 return (ENAMETOOLONG);
2440 NFSCL_REQSTART(nd, NFSPROC_RMDIR, dvp);
2441 (void) nfsm_strtom(nd, name, namelen);
2442 error = nfscl_request(nd, dvp, p, cred, dstuff);
2445 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
2446 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2447 if (nd->nd_repstat && !error)
2448 error = nd->nd_repstat;
2449 mbuf_freem(nd->nd_mrep);
2451 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
2453 if (error == ENOENT)
2460 * Always returns with either uio_resid unchanged, if you are at the
2461 * end of the directory, or uio_resid == 0, with all DIRBLKSIZ chunks
2463 * I felt this would allow caching of directory blocks more easily
2464 * than returning a pertially filled block.
2465 * Directory offset cookies:
2466 * Oh my, what to do with them...
2467 * I can think of three ways to deal with them:
2468 * 1 - have the layer above these RPCs maintain a map between logical
2469 * directory byte offsets and the NFS directory offset cookies
2470 * 2 - pass the opaque directory offset cookies up into userland
2471 * and let the libc functions deal with them, via the system call
2472 * 3 - return them to userland in the "struct dirent", so future versions
2473 * of libc can use them and do whatever is necessary to amke things work
2474 * above these rpc calls, in the meantime
2475 * For now, I do #3 by "hiding" the directory offset cookies after the
2476 * d_name field in struct dirent. This is space inside d_reclen that
2477 * will be ignored by anything that doesn't know about them.
2478 * The directory offset cookies are filled in as the last 8 bytes of
2479 * each directory entry, after d_name. Someday, the userland libc
2480 * functions may be able to use these. In the meantime, it satisfies
2481 * OpenBSD's requirements for cookies being returned.
2482 * If expects the directory offset cookie for the read to be in uio_offset
2483 * and returns the one for the next entry after this directory block in
2487 nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
2488 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
2489 int *eofp, void *stuff)
2492 struct dirent *dp = NULL;
2494 nfsquad_t cookie, ncookie;
2495 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
2496 struct nfsnode *dnp = VTONFS(vp);
2497 struct nfsvattr nfsva;
2498 struct nfsrv_descript nfsd, *nd = &nfsd;
2499 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
2500 int reqsize, tryformoredirs = 1, readsize, eof = 0, gotmnton = 0;
2501 long dotfileid, dotdotfileid = 0;
2502 u_int32_t fakefileno = 0xffffffff, rderr;
2504 nfsattrbit_t attrbits, dattrbits;
2505 u_int32_t *tl2 = NULL;
2508 KASSERT(uiop->uio_iovcnt == 1 &&
2509 (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0,
2510 ("nfs readdirrpc bad uio"));
2513 * There is no point in reading a lot more than uio_resid, however
2514 * adding one additional DIRBLKSIZ makes sense. Since uio_resid
2515 * and nm_readdirsize are both exact multiples of DIRBLKSIZ, this
2516 * will never make readsize > nm_readdirsize.
2518 readsize = nmp->nm_readdirsize;
2519 if (readsize > uio_uio_resid(uiop))
2520 readsize = uio_uio_resid(uiop) + DIRBLKSIZ;
2525 tresid = uio_uio_resid(uiop);
2526 cookie.lval[0] = cookiep->nfsuquad[0];
2527 cookie.lval[1] = cookiep->nfsuquad[1];
2531 * For NFSv4, first create the "." and ".." entries.
2533 if (NFSHASNFSV4(nmp)) {
2534 reqsize = 6 * NFSX_UNSIGNED;
2535 NFSGETATTR_ATTRBIT(&dattrbits);
2536 NFSZERO_ATTRBIT(&attrbits);
2537 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID);
2538 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TYPE);
2539 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
2540 NFSATTRBIT_MOUNTEDONFILEID)) {
2541 NFSSETBIT_ATTRBIT(&attrbits,
2542 NFSATTRBIT_MOUNTEDONFILEID);
2546 * Must fake it. Use the fileno, except when the
2547 * fsid is != to that of the directory. For that
2548 * case, generate a fake fileno that is not the same.
2550 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID);
2555 * Joy, oh joy. For V4 we get to hand craft '.' and '..'.
2557 if (uiop->uio_offset == 0) {
2558 #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000
2559 error = VOP_GETATTR(vp, &nfsva.na_vattr, cred);
2561 error = VOP_GETATTR(vp, &nfsva.na_vattr, cred, p);
2565 dotfileid = nfsva.na_fileid;
2566 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp);
2567 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2568 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
2569 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2570 (void) nfsrv_putattrbit(nd, &attrbits);
2571 error = nfscl_request(nd, vp, p, cred, stuff);
2574 if (nd->nd_repstat == 0) {
2575 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
2576 len = fxdr_unsigned(int, *(tl + 2));
2577 if (len > 0 && len <= NFSX_V4FHMAX)
2578 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
2582 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
2583 nfsva.na_mntonfileno = 0xffffffff;
2584 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
2585 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
2586 NULL, NULL, NULL, p, cred);
2588 dotdotfileid = dotfileid;
2589 } else if (gotmnton) {
2590 if (nfsva.na_mntonfileno != 0xffffffff)
2591 dotdotfileid = nfsva.na_mntonfileno;
2593 dotdotfileid = nfsva.na_fileid;
2594 } else if (nfsva.na_filesid[0] ==
2595 dnp->n_vattr.na_filesid[0] &&
2596 nfsva.na_filesid[1] ==
2597 dnp->n_vattr.na_filesid[1]) {
2598 dotdotfileid = nfsva.na_fileid;
2602 } while (fakefileno ==
2604 dotdotfileid = fakefileno;
2607 } else if (nd->nd_repstat == NFSERR_NOENT) {
2609 * Lookupp returns NFSERR_NOENT when we are
2610 * at the root, so just use the current dir.
2613 dotdotfileid = dotfileid;
2615 error = nd->nd_repstat;
2617 mbuf_freem(nd->nd_mrep);
2621 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
2622 dp->d_type = DT_DIR;
2623 dp->d_fileno = dotfileid;
2625 dp->d_name[0] = '.';
2626 dp->d_name[1] = '\0';
2627 dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
2629 * Just make these offset cookie 0.
2631 tl = (u_int32_t *)&dp->d_name[4];
2634 blksiz += dp->d_reclen;
2635 uio_uio_resid_add(uiop, -(dp->d_reclen));
2636 uiop->uio_offset += dp->d_reclen;
2637 uio_iov_base_add(uiop, dp->d_reclen);
2638 uio_iov_len_add(uiop, -(dp->d_reclen));
2639 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
2640 dp->d_type = DT_DIR;
2641 dp->d_fileno = dotdotfileid;
2643 dp->d_name[0] = '.';
2644 dp->d_name[1] = '.';
2645 dp->d_name[2] = '\0';
2646 dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
2648 * Just make these offset cookie 0.
2650 tl = (u_int32_t *)&dp->d_name[4];
2653 blksiz += dp->d_reclen;
2654 uio_uio_resid_add(uiop, -(dp->d_reclen));
2655 uiop->uio_offset += dp->d_reclen;
2656 uio_iov_base_add(uiop, dp->d_reclen);
2657 uio_iov_len_add(uiop, -(dp->d_reclen));
2659 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_RDATTRERROR);
2661 reqsize = 5 * NFSX_UNSIGNED;
2666 * Loop around doing readdir rpc's of size readsize.
2667 * The stopping criteria is EOF or buffer full.
2669 while (more_dirs && bigenough) {
2671 NFSCL_REQSTART(nd, NFSPROC_READDIR, vp);
2672 if (nd->nd_flag & ND_NFSV2) {
2673 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2674 *tl++ = cookie.lval[1];
2675 *tl = txdr_unsigned(readsize);
2677 NFSM_BUILD(tl, u_int32_t *, reqsize);
2678 *tl++ = cookie.lval[0];
2679 *tl++ = cookie.lval[1];
2680 if (cookie.qval == 0) {
2685 *tl++ = dnp->n_cookieverf.nfsuquad[0];
2686 *tl++ = dnp->n_cookieverf.nfsuquad[1];
2689 if (nd->nd_flag & ND_NFSV4) {
2690 *tl++ = txdr_unsigned(readsize);
2691 *tl = txdr_unsigned(readsize);
2692 (void) nfsrv_putattrbit(nd, &attrbits);
2693 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2694 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2695 (void) nfsrv_putattrbit(nd, &dattrbits);
2697 *tl = txdr_unsigned(readsize);
2700 error = nfscl_request(nd, vp, p, cred, stuff);
2703 if (!(nd->nd_flag & ND_NFSV2)) {
2704 if (nd->nd_flag & ND_NFSV3)
2705 error = nfscl_postop_attr(nd, nap, attrflagp,
2707 if (!nd->nd_repstat && !error) {
2708 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2710 dnp->n_cookieverf.nfsuquad[0] = *tl++;
2711 dnp->n_cookieverf.nfsuquad[1] = *tl;
2715 if (nd->nd_repstat || error) {
2717 error = nd->nd_repstat;
2720 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2721 more_dirs = fxdr_unsigned(int, *tl);
2725 /* loop thru the dir entries, doctoring them to 4bsd form */
2726 while (more_dirs && bigenough) {
2727 if (nd->nd_flag & ND_NFSV4) {
2728 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
2729 ncookie.lval[0] = *tl++;
2730 ncookie.lval[1] = *tl++;
2731 len = fxdr_unsigned(int, *tl);
2732 } else if (nd->nd_flag & ND_NFSV3) {
2733 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
2735 fxdr_unsigned(long, *++tl);
2736 len = fxdr_unsigned(int, *++tl);
2738 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
2740 fxdr_unsigned(long, *tl++);
2741 len = fxdr_unsigned(int, *tl);
2743 if (len <= 0 || len > NFS_MAXNAMLEN) {
2747 tlen = NFSM_RNDUP(len);
2749 tlen += 4; /* To ensure null termination */
2750 left = DIRBLKSIZ - blksiz;
2751 if ((int)(tlen + DIRHDSIZ + NFSX_HYPER) > left) {
2752 dp->d_reclen += left;
2753 uio_iov_base_add(uiop, left);
2754 uio_iov_len_add(uiop, -(left));
2755 uio_uio_resid_add(uiop, -(left));
2756 uiop->uio_offset += left;
2759 if ((int)(tlen + DIRHDSIZ + NFSX_HYPER) > uio_uio_resid(uiop))
2762 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
2764 dp->d_reclen = tlen + DIRHDSIZ + NFSX_HYPER;
2765 dp->d_type = DT_UNKNOWN;
2766 blksiz += dp->d_reclen;
2767 if (blksiz == DIRBLKSIZ)
2769 uio_uio_resid_add(uiop, -(DIRHDSIZ));
2770 uiop->uio_offset += DIRHDSIZ;
2771 uio_iov_base_add(uiop, DIRHDSIZ);
2772 uio_iov_len_add(uiop, -(DIRHDSIZ));
2773 error = nfsm_mbufuio(nd, uiop, len);
2776 cp = CAST_DOWN(caddr_t, uio_iov_base(uiop));
2778 *cp = '\0'; /* null terminate */
2779 cp += tlen; /* points to cookie storage */
2780 tl2 = (u_int32_t *)cp;
2781 uio_iov_base_add(uiop, (tlen + NFSX_HYPER));
2782 uio_iov_len_add(uiop, -(tlen + NFSX_HYPER));
2783 uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER));
2784 uiop->uio_offset += (tlen + NFSX_HYPER);
2786 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
2790 if (nd->nd_flag & ND_NFSV4) {
2792 nfsva.na_mntonfileno = 0xffffffff;
2793 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
2794 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
2795 NULL, NULL, &rderr, p, cred);
2798 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2799 } else if (nd->nd_flag & ND_NFSV3) {
2800 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
2801 ncookie.lval[0] = *tl++;
2802 ncookie.lval[1] = *tl++;
2804 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
2805 ncookie.lval[0] = 0;
2806 ncookie.lval[1] = *tl++;
2809 if (nd->nd_flag & ND_NFSV4) {
2814 if (nfsva.na_mntonfileno != 0xffffffff)
2815 dp->d_fileno = nfsva.na_mntonfileno;
2817 dp->d_fileno = nfsva.na_fileid;
2818 } else if (nfsva.na_filesid[0] ==
2819 dnp->n_vattr.na_filesid[0] &&
2820 nfsva.na_filesid[1] ==
2821 dnp->n_vattr.na_filesid[1]) {
2822 dp->d_fileno = nfsva.na_fileid;
2826 } while (fakefileno ==
2828 dp->d_fileno = fakefileno;
2830 dp->d_type = vtonfs_dtype(nfsva.na_type);
2833 dp->d_fileno = nfsva.na_fileid;
2835 *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] =
2837 *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] =
2840 more_dirs = fxdr_unsigned(int, *tl);
2843 * If at end of rpc data, get the eof boolean
2846 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2847 eof = fxdr_unsigned(int, *tl);
2850 if (nd->nd_flag & ND_NFSV4) {
2851 error = nfscl_postop_attr(nd, nap, attrflagp,
2857 mbuf_freem(nd->nd_mrep);
2861 * Fill last record, iff any, out to a multiple of DIRBLKSIZ
2862 * by increasing d_reclen for the last record.
2865 left = DIRBLKSIZ - blksiz;
2866 dp->d_reclen += left;
2867 uio_iov_base_add(uiop, left);
2868 uio_iov_len_add(uiop, -(left));
2869 uio_uio_resid_add(uiop, -(left));
2870 uiop->uio_offset += left;
2874 * If returning no data, assume end of file.
2875 * If not bigenough, return not end of file, since you aren't
2876 * returning all the data
2877 * Otherwise, return the eof flag from the server.
2880 if (tresid == ((size_t)(uio_uio_resid(uiop))))
2882 else if (!bigenough)
2889 * Add extra empty records to any remaining DIRBLKSIZ chunks.
2891 while (uio_uio_resid(uiop) > 0 && ((size_t)(uio_uio_resid(uiop))) != tresid) {
2892 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
2893 dp->d_type = DT_UNKNOWN;
2896 dp->d_name[0] = '\0';
2897 tl = (u_int32_t *)&dp->d_name[4];
2898 *tl++ = cookie.lval[0];
2899 *tl = cookie.lval[1];
2900 dp->d_reclen = DIRBLKSIZ;
2901 uio_iov_base_add(uiop, DIRBLKSIZ);
2902 uio_iov_len_add(uiop, -(DIRBLKSIZ));
2903 uio_uio_resid_add(uiop, -(DIRBLKSIZ));
2904 uiop->uio_offset += DIRBLKSIZ;
2908 if (nd->nd_mrep != NULL)
2909 mbuf_freem(nd->nd_mrep);
2915 * NFS V3 readdir plus RPC. Used in place of nfsrpc_readdir().
2916 * (Also used for NFS V4 when mount flag set.)
2917 * (ditto above w.r.t. multiple of DIRBLKSIZ, etc.)
2920 nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
2921 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
2922 int *eofp, void *stuff)
2925 struct dirent *dp = NULL;
2927 vnode_t newvp = NULLVP;
2928 struct nfsrv_descript nfsd, *nd = &nfsd;
2929 struct nameidata nami, *ndp = &nami;
2930 struct componentname *cnp = &ndp->ni_cnd;
2931 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
2932 struct nfsnode *dnp = VTONFS(vp), *np;
2933 struct nfsvattr nfsva;
2935 nfsquad_t cookie, ncookie;
2936 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
2937 int attrflag, tryformoredirs = 1, eof = 0, gotmnton = 0;
2938 int unlocknewvp = 0;
2939 long dotfileid, dotdotfileid = 0, fileno = 0;
2941 nfsattrbit_t attrbits, dattrbits;
2943 u_int32_t *tl2 = NULL, fakefileno = 0xffffffff, rderr;
2945 KASSERT(uiop->uio_iovcnt == 1 &&
2946 (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0,
2947 ("nfs readdirplusrpc bad uio"));
2953 cookie.lval[0] = cookiep->nfsuquad[0];
2954 cookie.lval[1] = cookiep->nfsuquad[1];
2955 tresid = uio_uio_resid(uiop);
2958 * For NFSv4, first create the "." and ".." entries.
2960 if (NFSHASNFSV4(nmp)) {
2961 NFSGETATTR_ATTRBIT(&dattrbits);
2962 NFSZERO_ATTRBIT(&attrbits);
2963 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID);
2964 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
2965 NFSATTRBIT_MOUNTEDONFILEID)) {
2966 NFSSETBIT_ATTRBIT(&attrbits,
2967 NFSATTRBIT_MOUNTEDONFILEID);
2971 * Must fake it. Use the fileno, except when the
2972 * fsid is != to that of the directory. For that
2973 * case, generate a fake fileno that is not the same.
2975 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID);
2980 * Joy, oh joy. For V4 we get to hand craft '.' and '..'.
2982 if (uiop->uio_offset == 0) {
2983 #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000
2984 error = VOP_GETATTR(vp, &nfsva.na_vattr, cred);
2986 error = VOP_GETATTR(vp, &nfsva.na_vattr, cred, p);
2990 dotfileid = nfsva.na_fileid;
2991 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp);
2992 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2993 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
2994 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2995 (void) nfsrv_putattrbit(nd, &attrbits);
2996 error = nfscl_request(nd, vp, p, cred, stuff);
2999 if (nd->nd_repstat == 0) {
3000 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3001 len = fxdr_unsigned(int, *(tl + 2));
3002 if (len > 0 && len <= NFSX_V4FHMAX)
3003 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
3007 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
3008 nfsva.na_mntonfileno = 0xffffffff;
3009 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
3010 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
3011 NULL, NULL, NULL, p, cred);
3013 dotdotfileid = dotfileid;
3014 } else if (gotmnton) {
3015 if (nfsva.na_mntonfileno != 0xffffffff)
3016 dotdotfileid = nfsva.na_mntonfileno;
3018 dotdotfileid = nfsva.na_fileid;
3019 } else if (nfsva.na_filesid[0] ==
3020 dnp->n_vattr.na_filesid[0] &&
3021 nfsva.na_filesid[1] ==
3022 dnp->n_vattr.na_filesid[1]) {
3023 dotdotfileid = nfsva.na_fileid;
3027 } while (fakefileno ==
3029 dotdotfileid = fakefileno;
3032 } else if (nd->nd_repstat == NFSERR_NOENT) {
3034 * Lookupp returns NFSERR_NOENT when we are
3035 * at the root, so just use the current dir.
3038 dotdotfileid = dotfileid;
3040 error = nd->nd_repstat;
3042 mbuf_freem(nd->nd_mrep);
3046 dp = (struct dirent *)uio_iov_base(uiop);
3047 dp->d_type = DT_DIR;
3048 dp->d_fileno = dotfileid;
3050 dp->d_name[0] = '.';
3051 dp->d_name[1] = '\0';
3052 dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
3054 * Just make these offset cookie 0.
3056 tl = (u_int32_t *)&dp->d_name[4];
3059 blksiz += dp->d_reclen;
3060 uio_uio_resid_add(uiop, -(dp->d_reclen));
3061 uiop->uio_offset += dp->d_reclen;
3062 uio_iov_base_add(uiop, dp->d_reclen);
3063 uio_iov_len_add(uiop, -(dp->d_reclen));
3064 dp = (struct dirent *)uio_iov_base(uiop);
3065 dp->d_type = DT_DIR;
3066 dp->d_fileno = dotdotfileid;
3068 dp->d_name[0] = '.';
3069 dp->d_name[1] = '.';
3070 dp->d_name[2] = '\0';
3071 dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
3073 * Just make these offset cookie 0.
3075 tl = (u_int32_t *)&dp->d_name[4];
3078 blksiz += dp->d_reclen;
3079 uio_uio_resid_add(uiop, -(dp->d_reclen));
3080 uiop->uio_offset += dp->d_reclen;
3081 uio_iov_base_add(uiop, dp->d_reclen);
3082 uio_iov_len_add(uiop, -(dp->d_reclen));
3084 NFSREADDIRPLUS_ATTRBIT(&attrbits);
3086 NFSSETBIT_ATTRBIT(&attrbits,
3087 NFSATTRBIT_MOUNTEDONFILEID);
3091 * Loop around doing readdir rpc's of size nm_readdirsize.
3092 * The stopping criteria is EOF or buffer full.
3094 while (more_dirs && bigenough) {
3096 NFSCL_REQSTART(nd, NFSPROC_READDIRPLUS, vp);
3097 NFSM_BUILD(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
3098 *tl++ = cookie.lval[0];
3099 *tl++ = cookie.lval[1];
3100 if (cookie.qval == 0) {
3105 *tl++ = dnp->n_cookieverf.nfsuquad[0];
3106 *tl++ = dnp->n_cookieverf.nfsuquad[1];
3109 *tl++ = txdr_unsigned(nmp->nm_readdirsize);
3110 *tl = txdr_unsigned(nmp->nm_readdirsize);
3111 if (nd->nd_flag & ND_NFSV4) {
3112 (void) nfsrv_putattrbit(nd, &attrbits);
3113 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3114 *tl = txdr_unsigned(NFSV4OP_GETATTR);
3115 (void) nfsrv_putattrbit(nd, &dattrbits);
3117 error = nfscl_request(nd, vp, p, cred, stuff);
3120 if (nd->nd_flag & ND_NFSV3)
3121 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3122 if (nd->nd_repstat || error) {
3124 error = nd->nd_repstat;
3127 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3129 dnp->n_cookieverf.nfsuquad[0] = *tl++;
3130 dnp->n_cookieverf.nfsuquad[1] = *tl++;
3132 more_dirs = fxdr_unsigned(int, *tl);
3136 /* loop thru the dir entries, doctoring them to 4bsd form */
3137 while (more_dirs && bigenough) {
3138 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3139 if (nd->nd_flag & ND_NFSV4) {
3140 ncookie.lval[0] = *tl++;
3141 ncookie.lval[1] = *tl++;
3143 fileno = fxdr_unsigned(long, *++tl);
3146 len = fxdr_unsigned(int, *tl);
3147 if (len <= 0 || len > NFS_MAXNAMLEN) {
3151 tlen = NFSM_RNDUP(len);
3153 tlen += 4; /* To ensure null termination */
3154 left = DIRBLKSIZ - blksiz;
3155 if ((tlen + DIRHDSIZ + NFSX_HYPER) > left) {
3156 dp->d_reclen += left;
3157 uio_iov_base_add(uiop, left);
3158 uio_iov_len_add(uiop, -(left));
3159 uio_uio_resid_add(uiop, -(left));
3160 uiop->uio_offset += left;
3163 if ((tlen + DIRHDSIZ + NFSX_HYPER) > uio_uio_resid(uiop))
3166 dp = (struct dirent *)uio_iov_base(uiop);
3168 dp->d_reclen = tlen + DIRHDSIZ + NFSX_HYPER;
3169 dp->d_type = DT_UNKNOWN;
3170 blksiz += dp->d_reclen;
3171 if (blksiz == DIRBLKSIZ)
3173 uio_uio_resid_add(uiop, -(DIRHDSIZ));
3174 uiop->uio_offset += DIRHDSIZ;
3175 uio_iov_base_add(uiop, DIRHDSIZ);
3176 uio_iov_len_add(uiop, -(DIRHDSIZ));
3177 cnp->cn_nameptr = uio_iov_base(uiop);
3178 cnp->cn_namelen = len;
3180 error = nfsm_mbufuio(nd, uiop, len);
3183 cp = uio_iov_base(uiop);
3186 cp += tlen; /* points to cookie storage */
3187 tl2 = (u_int32_t *)cp;
3188 uio_iov_base_add(uiop, (tlen + NFSX_HYPER));
3189 uio_iov_len_add(uiop, -(tlen + NFSX_HYPER));
3190 uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER));
3191 uiop->uio_offset += (tlen + NFSX_HYPER);
3193 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
3198 if (nd->nd_flag & ND_NFSV3) {
3199 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3200 ncookie.lval[0] = *tl++;
3201 ncookie.lval[1] = *tl++;
3202 attrflag = fxdr_unsigned(int, *tl);
3204 error = nfsm_loadattr(nd, &nfsva);
3208 NFSM_DISSECT(tl,u_int32_t *,NFSX_UNSIGNED);
3210 error = nfsm_getfh(nd, &nfhp);
3214 if (!attrflag && nfhp != NULL) {
3215 FREE((caddr_t)nfhp, M_NFSFH);
3220 nfsva.na_mntonfileno = 0xffffffff;
3221 error = nfsv4_loadattr(nd, NULL, &nfsva, &nfhp,
3222 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
3223 NULL, NULL, &rderr, p, cred);
3229 if (nd->nd_flag & ND_NFSV4) {
3232 } else if (gotmnton) {
3233 if (nfsva.na_mntonfileno != 0xffffffff)
3234 dp->d_fileno = nfsva.na_mntonfileno;
3236 dp->d_fileno = nfsva.na_fileid;
3237 } else if (nfsva.na_filesid[0] ==
3238 dnp->n_vattr.na_filesid[0] &&
3239 nfsva.na_filesid[1] ==
3240 dnp->n_vattr.na_filesid[1]) {
3241 dp->d_fileno = nfsva.na_fileid;
3245 } while (fakefileno ==
3247 dp->d_fileno = fakefileno;
3250 dp->d_fileno = fileno;
3252 *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] =
3254 *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] =
3258 if (NFSRV_CMPFH(nfhp->nfh_fh, nfhp->nfh_len,
3259 dnp->n_fhp->nfh_fh, dnp->n_fhp->nfh_len)) {
3263 FREE((caddr_t)nfhp, M_NFSFH);
3266 error = nfscl_nget(vnode_mount(vp), vp,
3267 nfhp, cnp, p, &np, NULL);
3274 if (newvp != NULLVP) {
3275 error = nfscl_loadattrcache(&newvp,
3276 &nfsva, NULL, NULL, 0, 0);
3285 vtonfs_dtype(np->n_vattr.na_type);
3287 NFSCNHASH(cnp, HASHINIT);
3288 if (cnp->cn_namelen <= NCHNAMLEN) {
3290 np->n_vattr.na_ctime.tv_sec;
3291 cache_enter(ndp->ni_dvp,ndp->ni_vp,cnp);
3300 } else if (nfhp != NULL) {
3301 FREE((caddr_t)nfhp, M_NFSFH);
3303 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3304 more_dirs = fxdr_unsigned(int, *tl);
3307 * If at end of rpc data, get the eof boolean
3310 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3311 eof = fxdr_unsigned(int, *tl);
3314 if (nd->nd_flag & ND_NFSV4) {
3315 error = nfscl_postop_attr(nd, nap, attrflagp,
3321 mbuf_freem(nd->nd_mrep);
3325 * Fill last record, iff any, out to a multiple of DIRBLKSIZ
3326 * by increasing d_reclen for the last record.
3329 left = DIRBLKSIZ - blksiz;
3330 dp->d_reclen += left;
3331 uio_iov_base_add(uiop, left);
3332 uio_iov_len_add(uiop, -(left));
3333 uio_uio_resid_add(uiop, -(left));
3334 uiop->uio_offset += left;
3338 * If returning no data, assume end of file.
3339 * If not bigenough, return not end of file, since you aren't
3340 * returning all the data
3341 * Otherwise, return the eof flag from the server.
3344 if (tresid == uio_uio_resid(uiop))
3346 else if (!bigenough)
3353 * Add extra empty records to any remaining DIRBLKSIZ chunks.
3355 while (uio_uio_resid(uiop) > 0 && uio_uio_resid(uiop) != tresid) {
3356 dp = (struct dirent *)uio_iov_base(uiop);
3357 dp->d_type = DT_UNKNOWN;
3360 dp->d_name[0] = '\0';
3361 tl = (u_int32_t *)&dp->d_name[4];
3362 *tl++ = cookie.lval[0];
3363 *tl = cookie.lval[1];
3364 dp->d_reclen = DIRBLKSIZ;
3365 uio_iov_base_add(uiop, DIRBLKSIZ);
3366 uio_iov_len_add(uiop, -(DIRBLKSIZ));
3367 uio_uio_resid_add(uiop, -(DIRBLKSIZ));
3368 uiop->uio_offset += DIRBLKSIZ;
3372 if (nd->nd_mrep != NULL)
3373 mbuf_freem(nd->nd_mrep);
3382 nfsrpc_commit(vnode_t vp, u_quad_t offset, int cnt, struct ucred *cred,
3383 NFSPROC_T *p, u_char *verfp, struct nfsvattr *nap, int *attrflagp,
3387 struct nfsrv_descript nfsd, *nd = &nfsd;
3388 nfsattrbit_t attrbits;
3392 NFSCL_REQSTART(nd, NFSPROC_COMMIT, vp);
3393 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3394 txdr_hyper(offset, tl);
3396 *tl = txdr_unsigned(cnt);
3397 if (nd->nd_flag & ND_NFSV4) {
3399 * And do a Getattr op.
3401 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3402 *tl = txdr_unsigned(NFSV4OP_GETATTR);
3403 NFSGETATTR_ATTRBIT(&attrbits);
3404 (void) nfsrv_putattrbit(nd, &attrbits);
3406 error = nfscl_request(nd, vp, p, cred, stuff);
3409 error = nfscl_wcc_data(nd, vp, nap, attrflagp, NULL, stuff);
3410 if (!error && !nd->nd_repstat) {
3411 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
3412 NFSBCOPY((caddr_t)tl, verfp, NFSX_VERF);
3413 if (nd->nd_flag & ND_NFSV4)
3414 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3417 if (!error && nd->nd_repstat)
3418 error = nd->nd_repstat;
3419 mbuf_freem(nd->nd_mrep);
3424 * NFS byte range lock rpc.
3425 * (Mostly just calls one of the three lower level RPC routines.)
3428 nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
3429 int reclaim, struct ucred *cred, NFSPROC_T *p)
3431 struct nfscllockowner *lp;
3432 struct nfsclclient *clp;
3434 struct nfsrv_descript nfsd, *nd = &nfsd;
3435 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
3438 u_int32_t clidrev = 0;
3439 int error = 0, newone = 0, expireret = 0, retrycnt, donelocally;
3443 * Convert the flock structure into a start and end and do POSIX
3446 switch (fl->l_whence) {
3450 * Caller is responsible for adding any necessary offset
3451 * when SEEK_CUR is used.
3453 start = fl->l_start;
3457 start = size + fl->l_start;
3458 off = size + fl->l_start;
3465 if (fl->l_len != 0) {
3466 end = start + fl->l_len - 1;
3477 if (op == F_GETLK) {
3478 error = nfscl_getcl(vp, cred, p, &clp);
3481 error = nfscl_lockt(vp, clp, off, len, fl, p);
3483 clidrev = clp->nfsc_clientidrev;
3484 error = nfsrpc_lockt(nd, vp, clp, off, len, fl, cred,
3486 } else if (error == -1) {
3489 nfscl_clientrelease(clp);
3490 } else if (op == F_UNLCK && fl->l_type == F_UNLCK) {
3492 * We must loop around for all lockowner cases.
3495 error = nfscl_getcl(vp, cred, p, &clp);
3499 error = nfscl_relbytelock(vp, off, len, cred, p, callcnt,
3502 * If it returns a NULL lp, we're done.
3506 nfscl_clientrelease(clp);
3508 nfscl_releasealllocks(clp, vp, p);
3511 if (nmp->nm_clp != NULL)
3512 clidrev = nmp->nm_clp->nfsc_clientidrev;
3516 * If the server doesn't support Posix lock semantics,
3517 * only allow locks on the entire file, since it won't
3518 * handle overlapping byte ranges.
3519 * There might still be a problem when a lock
3520 * upgrade/downgrade (read<->write) occurs, since the
3521 * server "might" expect an unlock first?
3523 if (dorpc && (lp->nfsl_open->nfso_posixlock ||
3524 (off == 0 && len == NFS64BITSSET))) {
3526 * Since the lock records will go away, we must
3527 * wait for grace and delay here.
3530 error = nfsrpc_locku(nd, nmp, lp, off, len,
3531 NFSV4LOCKT_READ, cred, p, 0);
3532 if ((nd->nd_repstat == NFSERR_GRACE ||
3533 nd->nd_repstat == NFSERR_DELAY) &&
3535 (void) nfs_catnap(PZERO, (int)nd->nd_repstat,
3537 } while ((nd->nd_repstat == NFSERR_GRACE ||
3538 nd->nd_repstat == NFSERR_DELAY) && error == 0);
3541 } while (error == 0 && nd->nd_repstat == 0);
3542 nfscl_releasealllocks(clp, vp, p);
3543 } else if (op == F_SETLK) {
3544 error = nfscl_getbytelock(vp, off, len, fl->l_type, cred, p,
3545 NULL, 0, NULL, NULL, &lp, &newone, &donelocally);
3546 if (error || donelocally) {
3549 if (nmp->nm_clp != NULL)
3550 clidrev = nmp->nm_clp->nfsc_clientidrev;
3553 nfhp = VTONFS(vp)->n_fhp;
3554 if (!lp->nfsl_open->nfso_posixlock &&
3555 (off != 0 || len != NFS64BITSSET)) {
3558 error = nfsrpc_lock(nd, nmp, vp, nfhp->nfh_fh,
3559 nfhp->nfh_len, lp, newone, reclaim, off,
3560 len, fl->l_type, cred, p, 0);
3563 error = nd->nd_repstat;
3564 nfscl_lockrelease(lp, error, newone);
3569 error = nd->nd_repstat;
3570 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
3571 error == NFSERR_STALEDONTRECOVER ||
3572 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY) {
3573 (void) nfs_catnap(PZERO, error, "nfs_advlock");
3574 } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID)
3576 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
3579 } while (error == NFSERR_GRACE ||
3580 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY ||
3581 error == NFSERR_STALEDONTRECOVER || error == NFSERR_STALESTATEID ||
3582 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
3583 expireret == 0 && clidrev != 0 && retrycnt < 4));
3584 if (error && retrycnt >= 4)
3590 * The lower level routine for the LockT case.
3593 nfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp,
3594 struct nfsclclient *clp, u_int64_t off, u_int64_t len, struct flock *fl,
3595 struct ucred *cred, NFSPROC_T *p)
3598 int error, type, size;
3599 u_int8_t own[NFSV4CL_LOCKNAMELEN];
3601 NFSCL_REQSTART(nd, NFSPROC_LOCKT, vp);
3602 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
3603 if (fl->l_type == F_RDLCK)
3604 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
3606 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
3607 txdr_hyper(off, tl);
3609 txdr_hyper(len, tl);
3611 *tl++ = clp->nfsc_clientid.lval[0];
3612 *tl = clp->nfsc_clientid.lval[1];
3613 nfscl_filllockowner(p, own);
3614 (void) nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN);
3615 error = nfscl_request(nd, vp, p, cred, NULL);
3618 if (nd->nd_repstat == 0) {
3619 fl->l_type = F_UNLCK;
3620 } else if (nd->nd_repstat == NFSERR_DENIED) {
3622 fl->l_whence = SEEK_SET;
3623 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
3624 fl->l_start = fxdr_hyper(tl);
3626 len = fxdr_hyper(tl);
3628 if (len == NFS64BITSSET)
3632 type = fxdr_unsigned(int, *tl++);
3633 if (type == NFSV4LOCKT_WRITE)
3634 fl->l_type = F_WRLCK;
3636 fl->l_type = F_RDLCK;
3638 * XXX For now, I have no idea what to do with the
3639 * conflicting lock_owner, so I'll just set the pid == 0
3640 * and skip over the lock_owner.
3642 fl->l_pid = (pid_t)0;
3644 size = fxdr_unsigned(int, *tl);
3645 if (size < 0 || size > NFSV4_OPAQUELIMIT)
3648 error = nfsm_advance(nd, NFSM_RNDUP(size), -1);
3649 } else if (nd->nd_repstat == NFSERR_STALECLIENTID)
3650 nfscl_initiate_recovery(clp);
3652 mbuf_freem(nd->nd_mrep);
3657 * Lower level function that performs the LockU RPC.
3660 nfsrpc_locku(struct nfsrv_descript *nd, struct nfsmount *nmp,
3661 struct nfscllockowner *lp, u_int64_t off, u_int64_t len,
3662 u_int32_t type, struct ucred *cred, NFSPROC_T *p, int syscred)
3667 nfscl_reqstart(nd, NFSPROC_LOCKU, nmp, lp->nfsl_open->nfso_fh,
3668 lp->nfsl_open->nfso_fhlen, NULL);
3669 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
3670 *tl++ = txdr_unsigned(type);
3671 *tl = txdr_unsigned(lp->nfsl_seqid);
3672 if (nfstest_outofseq &&
3673 (arc4random() % nfstest_outofseq) == 0)
3674 *tl = txdr_unsigned(lp->nfsl_seqid + 1);
3676 *tl++ = lp->nfsl_stateid.seqid;
3677 *tl++ = lp->nfsl_stateid.other[0];
3678 *tl++ = lp->nfsl_stateid.other[1];
3679 *tl++ = lp->nfsl_stateid.other[2];
3680 txdr_hyper(off, tl);
3682 txdr_hyper(len, tl);
3684 nd->nd_flag |= ND_USEGSSNAME;
3685 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
3686 NFS_PROG, NFS_VER4, NULL, 1, NULL);
3687 NFSCL_INCRSEQID(lp->nfsl_seqid, nd);
3690 if (nd->nd_repstat == 0) {
3691 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3692 lp->nfsl_stateid.seqid = *tl++;
3693 lp->nfsl_stateid.other[0] = *tl++;
3694 lp->nfsl_stateid.other[1] = *tl++;
3695 lp->nfsl_stateid.other[2] = *tl;
3696 } else if (nd->nd_repstat == NFSERR_STALESTATEID)
3697 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp);
3699 mbuf_freem(nd->nd_mrep);
3704 * The actual Lock RPC.
3707 nfsrpc_lock(struct nfsrv_descript *nd, struct nfsmount *nmp, vnode_t vp,
3708 u_int8_t *nfhp, int fhlen, struct nfscllockowner *lp, int newone,
3709 int reclaim, u_int64_t off, u_int64_t len, short type, struct ucred *cred,
3710 NFSPROC_T *p, int syscred)
3715 nfscl_reqstart(nd, NFSPROC_LOCK, nmp, nfhp, fhlen, NULL);
3716 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
3717 if (type == F_RDLCK)
3718 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
3720 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
3721 *tl++ = txdr_unsigned(reclaim);
3722 txdr_hyper(off, tl);
3724 txdr_hyper(len, tl);
3728 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID +
3729 2 * NFSX_UNSIGNED + NFSX_HYPER);
3730 *tl++ = txdr_unsigned(lp->nfsl_open->nfso_own->nfsow_seqid);
3731 *tl++ = lp->nfsl_open->nfso_stateid.seqid;
3732 *tl++ = lp->nfsl_open->nfso_stateid.other[0];
3733 *tl++ = lp->nfsl_open->nfso_stateid.other[1];
3734 *tl++ = lp->nfsl_open->nfso_stateid.other[2];
3735 *tl++ = txdr_unsigned(lp->nfsl_seqid);
3736 *tl++ = lp->nfsl_open->nfso_own->nfsow_clp->nfsc_clientid.lval[0];
3737 *tl = lp->nfsl_open->nfso_own->nfsow_clp->nfsc_clientid.lval[1];
3738 (void) nfsm_strtom(nd, lp->nfsl_owner, NFSV4CL_LOCKNAMELEN);
3741 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
3742 *tl++ = lp->nfsl_stateid.seqid;
3743 *tl++ = lp->nfsl_stateid.other[0];
3744 *tl++ = lp->nfsl_stateid.other[1];
3745 *tl++ = lp->nfsl_stateid.other[2];
3746 *tl = txdr_unsigned(lp->nfsl_seqid);
3747 if (nfstest_outofseq &&
3748 (arc4random() % nfstest_outofseq) == 0)
3749 *tl = txdr_unsigned(lp->nfsl_seqid + 1);
3752 nd->nd_flag |= ND_USEGSSNAME;
3753 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
3754 NFS_PROG, NFS_VER4, NULL, 1, NULL);
3758 NFSCL_INCRSEQID(lp->nfsl_open->nfso_own->nfsow_seqid, nd);
3759 NFSCL_INCRSEQID(lp->nfsl_seqid, nd);
3760 if (nd->nd_repstat == 0) {
3761 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3762 lp->nfsl_stateid.seqid = *tl++;
3763 lp->nfsl_stateid.other[0] = *tl++;
3764 lp->nfsl_stateid.other[1] = *tl++;
3765 lp->nfsl_stateid.other[2] = *tl;
3766 } else if (nd->nd_repstat == NFSERR_DENIED) {
3767 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
3768 size = fxdr_unsigned(int, *(tl + 7));
3769 if (size < 0 || size > NFSV4_OPAQUELIMIT)
3772 error = nfsm_advance(nd, NFSM_RNDUP(size), -1);
3773 } else if (nd->nd_repstat == NFSERR_STALESTATEID)
3774 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp);
3776 mbuf_freem(nd->nd_mrep);
3782 * (always called with the vp for the mount point)
3785 nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp,
3786 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
3789 u_int32_t *tl = NULL;
3790 struct nfsrv_descript nfsd, *nd = &nfsd;
3791 struct nfsmount *nmp;
3792 nfsattrbit_t attrbits;
3796 nmp = VFSTONFS(vnode_mount(vp));
3797 if (NFSHASNFSV4(nmp)) {
3799 * For V4, you actually do a getattr.
3801 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
3802 NFSSTATFS_GETATTRBIT(&attrbits);
3803 (void) nfsrv_putattrbit(nd, &attrbits);
3804 nd->nd_flag |= ND_USEGSSNAME;
3805 error = nfscl_request(nd, vp, p, cred, stuff);
3808 if (nd->nd_repstat == 0) {
3809 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
3810 NULL, NULL, sbp, fsp, NULL, 0, NULL, NULL, NULL, p,
3813 nmp->nm_fsid[0] = nap->na_filesid[0];
3814 nmp->nm_fsid[1] = nap->na_filesid[1];
3815 NFSSETHASSETFSID(nmp);
3819 error = nd->nd_repstat;
3824 NFSCL_REQSTART(nd, NFSPROC_FSSTAT, vp);
3825 error = nfscl_request(nd, vp, p, cred, stuff);
3828 if (nd->nd_flag & ND_NFSV3) {
3829 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3833 if (nd->nd_repstat) {
3834 error = nd->nd_repstat;
3837 NFSM_DISSECT(tl, u_int32_t *,
3838 NFSX_STATFS(nd->nd_flag & ND_NFSV3));
3840 if (NFSHASNFSV3(nmp)) {
3841 sbp->sf_tbytes = fxdr_hyper(tl); tl += 2;
3842 sbp->sf_fbytes = fxdr_hyper(tl); tl += 2;
3843 sbp->sf_abytes = fxdr_hyper(tl); tl += 2;
3844 sbp->sf_tfiles = fxdr_hyper(tl); tl += 2;
3845 sbp->sf_ffiles = fxdr_hyper(tl); tl += 2;
3846 sbp->sf_afiles = fxdr_hyper(tl); tl += 2;
3847 sbp->sf_invarsec = fxdr_unsigned(u_int32_t, *tl);
3848 } else if (NFSHASNFSV4(nmp) == 0) {
3849 sbp->sf_tsize = fxdr_unsigned(u_int32_t, *tl++);
3850 sbp->sf_bsize = fxdr_unsigned(u_int32_t, *tl++);
3851 sbp->sf_blocks = fxdr_unsigned(u_int32_t, *tl++);
3852 sbp->sf_bfree = fxdr_unsigned(u_int32_t, *tl++);
3853 sbp->sf_bavail = fxdr_unsigned(u_int32_t, *tl);
3856 mbuf_freem(nd->nd_mrep);
3864 nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc,
3865 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
3868 struct nfsrv_descript nfsd, *nd = &nfsd;
3869 struct nfsmount *nmp;
3871 nfsattrbit_t attrbits;
3875 nmp = VFSTONFS(vnode_mount(vp));
3876 if (NFSHASNFSV4(nmp)) {
3878 * For V4, you actually do a getattr.
3880 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
3881 NFSPATHCONF_GETATTRBIT(&attrbits);
3882 (void) nfsrv_putattrbit(nd, &attrbits);
3883 nd->nd_flag |= ND_USEGSSNAME;
3884 error = nfscl_request(nd, vp, p, cred, stuff);
3887 if (nd->nd_repstat == 0) {
3888 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
3889 pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, p,
3894 error = nd->nd_repstat;
3897 NFSCL_REQSTART(nd, NFSPROC_PATHCONF, vp);
3898 error = nfscl_request(nd, vp, p, cred, stuff);
3901 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3902 if (nd->nd_repstat && !error)
3903 error = nd->nd_repstat;
3905 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3PATHCONF);
3906 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl++);
3907 pc->pc_namemax = fxdr_unsigned(u_int32_t, *tl++);
3908 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl++);
3909 pc->pc_chownrestricted =
3910 fxdr_unsigned(u_int32_t, *tl++);
3911 pc->pc_caseinsensitive =
3912 fxdr_unsigned(u_int32_t, *tl++);
3913 pc->pc_casepreserving = fxdr_unsigned(u_int32_t, *tl);
3917 mbuf_freem(nd->nd_mrep);
3922 * nfs version 3 fsinfo rpc call
3925 nfsrpc_fsinfo(vnode_t vp, struct nfsfsinfo *fsp, struct ucred *cred,
3926 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
3929 struct nfsrv_descript nfsd, *nd = &nfsd;
3933 NFSCL_REQSTART(nd, NFSPROC_FSINFO, vp);
3934 error = nfscl_request(nd, vp, p, cred, stuff);
3937 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3938 if (nd->nd_repstat && !error)
3939 error = nd->nd_repstat;
3941 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3FSINFO);
3942 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *tl++);
3943 fsp->fs_rtpref = fxdr_unsigned(u_int32_t, *tl++);
3944 fsp->fs_rtmult = fxdr_unsigned(u_int32_t, *tl++);
3945 fsp->fs_wtmax = fxdr_unsigned(u_int32_t, *tl++);
3946 fsp->fs_wtpref = fxdr_unsigned(u_int32_t, *tl++);
3947 fsp->fs_wtmult = fxdr_unsigned(u_int32_t, *tl++);
3948 fsp->fs_dtpref = fxdr_unsigned(u_int32_t, *tl++);
3949 fsp->fs_maxfilesize = fxdr_hyper(tl);
3951 fxdr_nfsv3time(tl, &fsp->fs_timedelta);
3953 fsp->fs_properties = fxdr_unsigned(u_int32_t, *tl);
3956 mbuf_freem(nd->nd_mrep);
3961 * This function performs the Renew RPC.
3964 nfsrpc_renew(struct nfsclclient *clp, struct ucred *cred, NFSPROC_T *p)
3967 struct nfsrv_descript nfsd;
3968 struct nfsrv_descript *nd = &nfsd;
3969 struct nfsmount *nmp;
3972 nmp = clp->nfsc_nmp;
3975 nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL);
3976 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3977 *tl++ = clp->nfsc_clientid.lval[0];
3978 *tl = clp->nfsc_clientid.lval[1];
3979 nd->nd_flag |= ND_USEGSSNAME;
3980 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
3981 NFS_PROG, NFS_VER4, NULL, 1, NULL);
3984 error = nd->nd_repstat;
3985 mbuf_freem(nd->nd_mrep);
3990 * This function performs the Releaselockowner RPC.
3993 nfsrpc_rellockown(struct nfsmount *nmp, struct nfscllockowner *lp,
3994 struct ucred *cred, NFSPROC_T *p)
3996 struct nfsrv_descript nfsd, *nd = &nfsd;
4000 nfscl_reqstart(nd, NFSPROC_RELEASELCKOWN, nmp, NULL, 0, NULL);
4001 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4002 *tl++ = nmp->nm_clp->nfsc_clientid.lval[0];
4003 *tl = nmp->nm_clp->nfsc_clientid.lval[1];
4004 (void) nfsm_strtom(nd, lp->nfsl_owner, NFSV4CL_LOCKNAMELEN);
4005 nd->nd_flag |= ND_USEGSSNAME;
4006 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4007 NFS_PROG, NFS_VER4, NULL, 1, NULL);
4010 error = nd->nd_repstat;
4011 mbuf_freem(nd->nd_mrep);
4016 * This function performs the Compound to get the mount pt FH.
4019 nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred,
4023 struct nfsrv_descript nfsd;
4024 struct nfsrv_descript *nd = &nfsd;
4026 int error, cnt, len, setnil;
4029 nfscl_reqstart(nd, NFSPROC_PUTROOTFH, nmp, NULL, 0, &opcntp);
4037 while (*cp2 != '\0' && *cp2 != '/')
4044 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4045 *tl = txdr_unsigned(NFSV4OP_LOOKUP);
4046 nfsm_strtom(nd, cp, strlen(cp));
4052 } while (*cp != '\0');
4053 *opcntp = txdr_unsigned(2 + cnt);
4054 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4055 *tl = txdr_unsigned(NFSV4OP_GETFH);
4056 nd->nd_flag |= ND_USEGSSNAME;
4057 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4058 NFS_PROG, NFS_VER4, NULL, 1, NULL);
4061 if (nd->nd_repstat == 0) {
4062 NFSM_DISSECT(tl, u_int32_t *, (3 + 2 * cnt) * NFSX_UNSIGNED);
4063 tl += (2 + 2 * cnt);
4064 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
4066 nd->nd_repstat = NFSERR_BADXDR;
4068 nd->nd_repstat = nfsrv_mtostr(nd, nmp->nm_fh, len);
4069 if (nd->nd_repstat == 0)
4070 nmp->nm_fhsize = len;
4073 error = nd->nd_repstat;
4075 mbuf_freem(nd->nd_mrep);
4080 * This function performs the Delegreturn RPC.
4083 nfsrpc_delegreturn(struct nfscldeleg *dp, struct ucred *cred,
4084 struct nfsmount *nmp, NFSPROC_T *p, int syscred)
4087 struct nfsrv_descript nfsd;
4088 struct nfsrv_descript *nd = &nfsd;
4091 nfscl_reqstart(nd, NFSPROC_DELEGRETURN, nmp, dp->nfsdl_fh,
4092 dp->nfsdl_fhlen, NULL);
4093 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
4094 *tl++ = dp->nfsdl_stateid.seqid;
4095 *tl++ = dp->nfsdl_stateid.other[0];
4096 *tl++ = dp->nfsdl_stateid.other[1];
4097 *tl = dp->nfsdl_stateid.other[2];
4099 nd->nd_flag |= ND_USEGSSNAME;
4100 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4101 NFS_PROG, NFS_VER4, NULL, 1, NULL);
4104 error = nd->nd_repstat;
4105 mbuf_freem(nd->nd_mrep);
4109 #ifdef NFS4_ACL_EXTATTR_NAME
4114 nfsrpc_getacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
4115 struct acl *aclp, void *stuff)
4117 struct nfsrv_descript nfsd, *nd = &nfsd;
4119 nfsattrbit_t attrbits;
4120 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
4122 if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp))
4123 return (EOPNOTSUPP);
4124 NFSCL_REQSTART(nd, NFSPROC_GETACL, vp);
4125 NFSZERO_ATTRBIT(&attrbits);
4126 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
4127 (void) nfsrv_putattrbit(nd, &attrbits);
4128 error = nfscl_request(nd, vp, p, cred, stuff);
4131 if (!nd->nd_repstat)
4132 error = nfsv4_loadattr(nd, vp, NULL, NULL, NULL, 0, NULL,
4133 NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, p, cred);
4135 error = nd->nd_repstat;
4136 mbuf_freem(nd->nd_mrep);
4144 nfsrpc_setacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
4145 struct acl *aclp, void *stuff)
4148 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
4150 if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp))
4151 return (EOPNOTSUPP);
4152 error = nfsrpc_setattr(vp, NULL, aclp, cred, p, NULL, NULL, stuff);
4160 nfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
4161 struct acl *aclp, nfsv4stateid_t *stateidp, void *stuff)
4163 struct nfsrv_descript nfsd, *nd = &nfsd;
4165 nfsattrbit_t attrbits;
4166 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
4168 if (!NFSHASNFSV4(nmp))
4169 return (EOPNOTSUPP);
4170 NFSCL_REQSTART(nd, NFSPROC_SETACL, vp);
4171 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
4172 NFSZERO_ATTRBIT(&attrbits);
4173 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
4174 (void) nfsv4_fillattr(nd, vp, aclp, NULL, NULL, 0, &attrbits,
4176 error = nfscl_request(nd, vp, p, cred, stuff);
4179 /* Don't care about the pre/postop attributes */
4180 mbuf_freem(nd->nd_mrep);
4181 return (nd->nd_repstat);
4184 #endif /* NFS4_ACL_EXTATTR_NAME */