Deleted Added
full compact
nfs_clrpcops.c (229802) nfs_clrpcops.c (230394)
1/*-
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
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.
19 *
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
30 * SUCH DAMAGE.
31 *
32 */
33
34#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
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.
19 *
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
30 * SUCH DAMAGE.
31 *
32 */
33
34#include <sys/cdefs.h>
35__FBSDID("$FreeBSD: head/sys/fs/nfsclient/nfs_clrpcops.c 229802 2012-01-08 01:54:46Z rmacklem $");
35__FBSDID("$FreeBSD: head/sys/fs/nfsclient/nfs_clrpcops.c 230394 2012-01-20 20:02:01Z jhb $");
36
37/*
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.
43 */
44
45#ifndef APPLEKEXT
46#include "opt_inet6.h"
47
48#include <fs/nfs/nfsport.h>
49
50/*
51 * Global variables
52 */
53extern int nfs_numnfscbd;
54extern struct timeval nfsboottime;
55extern u_int32_t newnfs_false, newnfs_true;
56extern nfstype nfsv34_type[9];
57extern int nfsrv_useacl;
58extern char nfsv4_callbackaddr[INET6_ADDRSTRLEN];
59NFSCLSTATEMUTEX;
60int nfstest_outofseq = 0;
61int nfscl_assumeposixlocks = 1;
62int nfscl_enablecallb = 0;
63short nfsv4_cbport = NFSV4_CBPORT;
64int nfstest_openallsetattr = 0;
65#endif /* !APPLEKEXT */
66
67#define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1))
68
69static int nfsrpc_setattrrpc(vnode_t , struct vattr *, nfsv4stateid_t *,
70 struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, void *);
71static int nfsrpc_readrpc(vnode_t , struct uio *, struct ucred *,
72 nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *, void *);
73static int nfsrpc_writerpc(vnode_t , struct uio *, int *, int *,
74 struct ucred *, nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *,
75 void *);
76static int nfsrpc_createv23(vnode_t , char *, int, struct vattr *,
77 nfsquad_t, int, struct ucred *, NFSPROC_T *, struct nfsvattr *,
78 struct nfsvattr *, struct nfsfh **, int *, int *, void *);
79static int nfsrpc_createv4(vnode_t , char *, int, struct vattr *,
80 nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, struct ucred *,
81 NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, struct nfsfh **, int *,
82 int *, void *, int *);
83static int nfsrpc_locku(struct nfsrv_descript *, struct nfsmount *,
84 struct nfscllockowner *, u_int64_t, u_int64_t,
85 u_int32_t, struct ucred *, NFSPROC_T *, int);
86static int nfsrpc_setaclrpc(vnode_t, struct ucred *, NFSPROC_T *,
87 struct acl *, nfsv4stateid_t *, void *);
88
89/*
90 * nfs null call from vfs.
91 */
92APPLESTATIC int
93nfsrpc_null(vnode_t vp, struct ucred *cred, NFSPROC_T *p)
94{
95 int error;
96 struct nfsrv_descript nfsd, *nd = &nfsd;
97
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);
103 return (error);
104}
105
106/*
107 * nfs access rpc op.
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.
110 */
111APPLESTATIC int
112nfsrpc_access(vnode_t vp, int acmode, struct ucred *cred,
113 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp)
114{
115 int error;
116 u_int32_t mode, rmode;
117
118 if (acmode & VREAD)
119 mode = NFSACCESS_READ;
120 else
121 mode = 0;
122 if (vnode_vtype(vp) == VDIR) {
123 if (acmode & VWRITE)
124 mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND |
125 NFSACCESS_DELETE);
126 if (acmode & VEXEC)
127 mode |= NFSACCESS_LOOKUP;
128 } else {
129 if (acmode & VWRITE)
130 mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND);
131 if (acmode & VEXEC)
132 mode |= NFSACCESS_EXECUTE;
133 }
134
135 /*
136 * Now, just call nfsrpc_accessrpc() to do the actual RPC.
137 */
138 error = nfsrpc_accessrpc(vp, mode, cred, p, nap, attrflagp, &rmode,
139 NULL);
140
141 /*
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...
145 */
146 if (!error && (rmode & mode) != mode)
147 error = EACCES;
148 return (error);
149}
150
151/*
152 * The actual rpc, separated out for Darwin.
153 */
154APPLESTATIC int
155nfsrpc_accessrpc(vnode_t vp, u_int32_t mode, struct ucred *cred,
156 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, u_int32_t *rmodep,
157 void *stuff)
158{
159 u_int32_t *tl;
160 u_int32_t supported, rmode;
161 int error;
162 struct nfsrv_descript nfsd, *nd = &nfsd;
163 nfsattrbit_t attrbits;
164
165 *attrflagp = 0;
166 supported = mode;
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) {
171 /*
172 * And do a Getattr op.
173 */
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);
178 }
179 error = nfscl_request(nd, vp, p, cred, stuff);
180 if (error)
181 return (error);
182 if (nd->nd_flag & ND_NFSV3) {
183 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
184 if (error)
185 goto nfsmout;
186 }
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++);
191 } else {
192 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
193 }
194 rmode = fxdr_unsigned(u_int32_t, *tl);
195 if (nd->nd_flag & ND_NFSV4)
196 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
197
198 /*
199 * It's not obvious what should be done about
200 * unsupported access modes. For now, be paranoid
201 * and clear the unsupported ones.
202 */
203 rmode &= supported;
204 *rmodep = rmode;
205 } else
206 error = nd->nd_repstat;
207nfsmout:
208 mbuf_freem(nd->nd_mrep);
209 return (error);
210}
211
212/*
213 * nfs open rpc
214 */
215APPLESTATIC int
216nfsrpc_open(vnode_t vp, int amode, struct ucred *cred, NFSPROC_T *p)
217{
218 struct nfsclopen *op;
219 struct nfscldeleg *dp;
220 struct nfsfh *nfhp;
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;
225
226 /*
227 * For NFSv4, Open Ops are only done on Regular Files.
228 */
229 if (vnode_vtype(vp) != VREG)
230 return (0);
231 mode = 0;
232 if (amode & FREAD)
233 mode |= NFSV4OPEN_ACCESSREAD;
234 if (amode & FWRITE)
235 mode |= NFSV4OPEN_ACCESSWRITE;
236 nfhp = np->n_fhp;
237
238 retrycnt = 0;
239#ifdef notdef
240{ char name[100]; int namel;
241namel = (np->n_v4->n4_namelen < 100) ? np->n_v4->n4_namelen : 99;
242bcopy(NFS4NODENAME(np->n_v4), name, namel);
243name[namel] = '\0';
244printf("rpcopen p=0x%x name=%s",p->p_pid,name);
245if (nfhp->nfh_len > 0) printf(" fh=0x%x\n",nfhp->nfh_fh[12]);
246else printf(" fhl=0\n");
247}
248#endif
249 do {
250 dp = NULL;
251 error = nfscl_open(vp, nfhp->nfh_fh, nfhp->nfh_len, mode, 1,
252 cred, p, NULL, &op, &newone, &ret, 1);
253 if (error) {
254 return (error);
255 }
256 if (nmp->nm_clp != NULL)
257 clidrev = nmp->nm_clp->nfsc_clientidrev;
258 else
259 clidrev = 0;
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);
267 if (dp != NULL) {
268#ifdef APPLE
269 OSBitAndAtomic((int32_t)~NDELEGMOD, (UInt32 *)&np->n_flag);
270#else
271 NFSLOCKNODE(np);
272 np->n_flag &= ~NDELEGMOD;
273 /*
274 * Invalidate the attribute cache, so that
275 * attributes that pre-date the issue of a
276 * delegation are not cached, since the
277 * cached attributes will remain valid while
278 * the delegation is held.
279 */
280 NFSINVALATTRCACHE(np);
281 NFSUNLOCKNODE(np);
282#endif
283 (void) nfscl_deleg(nmp->nm_mountp,
284 op->nfso_own->nfsow_clp,
285 nfhp->nfh_fh, nfhp->nfh_len, cred, p, &dp);
286 }
287 } else {
288 error = EIO;
289 }
290 newnfs_copyincred(cred, &op->nfso_cred);
291 } else if (ret == NFSCLOPEN_SETCRED)
292 /*
293 * This is a new local open on a delegation. It needs
294 * to have credentials so that an open can be done
295 * against the server during recovery.
296 */
297 newnfs_copyincred(cred, &op->nfso_cred);
298
299 /*
300 * nfso_opencnt is the count of how many VOP_OPEN()s have
301 * been done on this Open successfully and a VOP_CLOSE()
302 * is expected for each of these.
303 * If error is non-zero, don't increment it, since the Open
304 * hasn't succeeded yet.
305 */
306 if (!error)
307 op->nfso_opencnt++;
308 nfscl_openrelease(op, error, newone);
309 if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
310 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY) {
311 (void) nfs_catnap(PZERO, error, "nfs_open");
312 } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID)
313 && clidrev != 0) {
314 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
315 retrycnt++;
316 }
317 } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
318 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
319 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
320 expireret == 0 && clidrev != 0 && retrycnt < 4));
321 if (error && retrycnt >= 4)
322 error = EIO;
323 return (error);
324}
325
326/*
327 * the actual open rpc
328 */
329APPLESTATIC int
330nfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen,
331 u_int8_t *newfhp, int newfhlen, u_int32_t mode, struct nfsclopen *op,
332 u_int8_t *name, int namelen, struct nfscldeleg **dpp,
333 int reclaim, u_int32_t delegtype, struct ucred *cred, NFSPROC_T *p,
334 int syscred, int recursed)
335{
336 u_int32_t *tl;
337 struct nfsrv_descript nfsd, *nd = &nfsd;
338 struct nfscldeleg *dp, *ndp = NULL;
339 struct nfsvattr nfsva;
340 u_int32_t rflags, deleg;
341 nfsattrbit_t attrbits;
342 int error, ret, acesize, limitby;
343
344 dp = *dpp;
345 *dpp = NULL;
346 nfscl_reqstart(nd, NFSPROC_OPEN, nmp, nfhp, fhlen, NULL);
347 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
348 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
349 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
350 *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
351 *tl++ = op->nfso_own->nfsow_clp->nfsc_clientid.lval[0];
352 *tl = op->nfso_own->nfsow_clp->nfsc_clientid.lval[1];
353 (void) nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN);
354 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
355 *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE);
356 if (reclaim) {
357 *tl = txdr_unsigned(NFSV4OPEN_CLAIMPREVIOUS);
358 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
359 *tl = txdr_unsigned(delegtype);
360 } else {
361 if (dp != NULL) {
362 *tl = txdr_unsigned(NFSV4OPEN_CLAIMDELEGATECUR);
363 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
364 *tl++ = dp->nfsdl_stateid.seqid;
365 *tl++ = dp->nfsdl_stateid.other[0];
366 *tl++ = dp->nfsdl_stateid.other[1];
367 *tl = dp->nfsdl_stateid.other[2];
368 } else {
369 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
370 }
371 (void) nfsm_strtom(nd, name, namelen);
372 }
373 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
374 *tl = txdr_unsigned(NFSV4OP_GETATTR);
375 NFSZERO_ATTRBIT(&attrbits);
376 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
377 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY);
378 (void) nfsrv_putattrbit(nd, &attrbits);
379 if (syscred)
380 nd->nd_flag |= ND_USEGSSNAME;
381 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
382 NFS_PROG, NFS_VER4, NULL, 1, NULL);
383 if (error)
384 return (error);
385 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
386 if (!nd->nd_repstat) {
387 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
388 6 * NFSX_UNSIGNED);
389 op->nfso_stateid.seqid = *tl++;
390 op->nfso_stateid.other[0] = *tl++;
391 op->nfso_stateid.other[1] = *tl++;
392 op->nfso_stateid.other[2] = *tl;
393 rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
394 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
395 if (error)
396 goto nfsmout;
397 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
398 deleg = fxdr_unsigned(u_int32_t, *tl);
399 if (deleg == NFSV4OPEN_DELEGATEREAD ||
400 deleg == NFSV4OPEN_DELEGATEWRITE) {
401 if (!(op->nfso_own->nfsow_clp->nfsc_flags &
402 NFSCLFLAGS_FIRSTDELEG))
403 op->nfso_own->nfsow_clp->nfsc_flags |=
404 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
405 MALLOC(ndp, struct nfscldeleg *,
406 sizeof (struct nfscldeleg) + newfhlen,
407 M_NFSCLDELEG, M_WAITOK);
408 LIST_INIT(&ndp->nfsdl_owner);
409 LIST_INIT(&ndp->nfsdl_lock);
410 ndp->nfsdl_clp = op->nfso_own->nfsow_clp;
411 ndp->nfsdl_fhlen = newfhlen;
412 NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen);
413 newnfs_copyincred(cred, &ndp->nfsdl_cred);
414 nfscl_lockinit(&ndp->nfsdl_rwlock);
415 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
416 NFSX_UNSIGNED);
417 ndp->nfsdl_stateid.seqid = *tl++;
418 ndp->nfsdl_stateid.other[0] = *tl++;
419 ndp->nfsdl_stateid.other[1] = *tl++;
420 ndp->nfsdl_stateid.other[2] = *tl++;
421 ret = fxdr_unsigned(int, *tl);
422 if (deleg == NFSV4OPEN_DELEGATEWRITE) {
423 ndp->nfsdl_flags = NFSCLDL_WRITE;
424 /*
425 * Indicates how much the file can grow.
426 */
427 NFSM_DISSECT(tl, u_int32_t *,
428 3 * NFSX_UNSIGNED);
429 limitby = fxdr_unsigned(int, *tl++);
430 switch (limitby) {
431 case NFSV4OPEN_LIMITSIZE:
432 ndp->nfsdl_sizelimit = fxdr_hyper(tl);
433 break;
434 case NFSV4OPEN_LIMITBLOCKS:
435 ndp->nfsdl_sizelimit =
436 fxdr_unsigned(u_int64_t, *tl++);
437 ndp->nfsdl_sizelimit *=
438 fxdr_unsigned(u_int64_t, *tl);
439 break;
440 default:
441 error = NFSERR_BADXDR;
442 goto nfsmout;
443 };
444 } else {
445 ndp->nfsdl_flags = NFSCLDL_READ;
446 }
447 if (ret)
448 ndp->nfsdl_flags |= NFSCLDL_RECALL;
449 error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, &ret,
450 &acesize, p);
451 if (error)
452 goto nfsmout;
453 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
454 error = NFSERR_BADXDR;
455 goto nfsmout;
456 }
457 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
458 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
459 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
460 NULL, NULL, NULL, p, cred);
461 if (error)
462 goto nfsmout;
463 if (ndp != NULL) {
464 ndp->nfsdl_change = nfsva.na_filerev;
465 ndp->nfsdl_modtime = nfsva.na_mtime;
466 ndp->nfsdl_flags |= NFSCLDL_MODTIMESET;
467 }
468 if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM)) {
469 do {
470 ret = nfsrpc_openconfirm(vp, newfhp, newfhlen, op,
471 cred, p);
472 if (ret == NFSERR_DELAY)
473 (void) nfs_catnap(PZERO, ret, "nfs_open");
474 } while (ret == NFSERR_DELAY);
475 error = ret;
476 }
477 if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) ||
478 nfscl_assumeposixlocks)
479 op->nfso_posixlock = 1;
480 else
481 op->nfso_posixlock = 0;
482
483 /*
484 * If the server is handing out delegations, but we didn't
485 * get one because an OpenConfirm was required, try the
486 * Open again, to get a delegation. This is a harmless no-op,
487 * from a server's point of view.
488 */
489 if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM) &&
490 (op->nfso_own->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG)
491 && !error && dp == NULL && ndp == NULL && !recursed) {
492 do {
493 ret = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp,
494 newfhlen, mode, op, name, namelen, &ndp, 0, 0x0,
495 cred, p, syscred, 1);
496 if (ret == NFSERR_DELAY)
497 (void) nfs_catnap(PZERO, ret, "nfs_open2");
498 } while (ret == NFSERR_DELAY);
499 if (ret) {
500 if (ndp != NULL)
501 FREE((caddr_t)ndp, M_NFSCLDELEG);
502 if (ret == NFSERR_STALECLIENTID ||
503 ret == NFSERR_STALEDONTRECOVER)
504 error = ret;
505 }
506 }
507 }
508 if (nd->nd_repstat != 0 && error == 0)
509 error = nd->nd_repstat;
510 if (error == NFSERR_STALECLIENTID)
511 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
512nfsmout:
513 if (!error)
514 *dpp = ndp;
515 else if (ndp != NULL)
516 FREE((caddr_t)ndp, M_NFSCLDELEG);
517 mbuf_freem(nd->nd_mrep);
518 return (error);
519}
520
521/*
522 * open downgrade rpc
523 */
524APPLESTATIC int
525nfsrpc_opendowngrade(vnode_t vp, u_int32_t mode, struct nfsclopen *op,
526 struct ucred *cred, NFSPROC_T *p)
527{
528 u_int32_t *tl;
529 struct nfsrv_descript nfsd, *nd = &nfsd;
530 int error;
531
532 NFSCL_REQSTART(nd, NFSPROC_OPENDOWNGRADE, vp);
533 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
534 *tl++ = op->nfso_stateid.seqid;
535 *tl++ = op->nfso_stateid.other[0];
536 *tl++ = op->nfso_stateid.other[1];
537 *tl++ = op->nfso_stateid.other[2];
538 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
539 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
540 *tl = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
541 error = nfscl_request(nd, vp, p, cred, NULL);
542 if (error)
543 return (error);
544 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
545 if (!nd->nd_repstat) {
546 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
547 op->nfso_stateid.seqid = *tl++;
548 op->nfso_stateid.other[0] = *tl++;
549 op->nfso_stateid.other[1] = *tl++;
550 op->nfso_stateid.other[2] = *tl;
551 }
552 if (nd->nd_repstat && error == 0)
553 error = nd->nd_repstat;
554 if (error == NFSERR_STALESTATEID)
555 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
556nfsmout:
557 mbuf_freem(nd->nd_mrep);
558 return (error);
559}
560
561/*
562 * V4 Close operation.
563 */
564APPLESTATIC int
565nfsrpc_close(vnode_t vp, int doclose, NFSPROC_T *p)
566{
567 struct nfsclclient *clp;
568 int error;
569
570 if (vnode_vtype(vp) != VREG)
571 return (0);
572 if (doclose)
573 error = nfscl_doclose(vp, &clp, p);
574 else
575 error = nfscl_getclose(vp, &clp);
576 if (error)
577 return (error);
578
579 nfscl_clientrelease(clp);
580 return (0);
581}
582
583/*
584 * Close the open.
585 */
586APPLESTATIC void
587nfsrpc_doclose(struct nfsmount *nmp, struct nfsclopen *op, NFSPROC_T *p)
588{
589 struct nfsrv_descript nfsd, *nd = &nfsd;
590 struct nfscllockowner *lp, *nlp;
591 struct nfscllock *lop, *nlop;
592 struct ucred *tcred;
593 u_int64_t off = 0, len = 0;
594 u_int32_t type = NFSV4LOCKT_READ;
595 int error, do_unlock, trycnt;
596
597 tcred = newnfs_getcred();
598 newnfs_copycred(&op->nfso_cred, tcred);
599 /*
600 * (Theoretically this could be done in the same
601 * compound as the close, but having multiple
602 * sequenced Ops in the same compound might be
603 * too scary for some servers.)
604 */
605 if (op->nfso_posixlock) {
606 off = 0;
607 len = NFS64BITSSET;
608 type = NFSV4LOCKT_READ;
609 }
610
611 /*
612 * Since this function is only called from VOP_INACTIVE(), no
613 * other thread will be manipulating this Open. As such, the
614 * lock lists are not being changed by other threads, so it should
615 * be safe to do this without locking.
616 */
617 LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) {
618 do_unlock = 1;
619 LIST_FOREACH_SAFE(lop, &lp->nfsl_lock, nfslo_list, nlop) {
620 if (op->nfso_posixlock == 0) {
621 off = lop->nfslo_first;
622 len = lop->nfslo_end - lop->nfslo_first;
623 if (lop->nfslo_type == F_WRLCK)
624 type = NFSV4LOCKT_WRITE;
625 else
626 type = NFSV4LOCKT_READ;
627 }
628 if (do_unlock) {
629 trycnt = 0;
630 do {
631 error = nfsrpc_locku(nd, nmp, lp, off,
632 len, type, tcred, p, 0);
633 if ((nd->nd_repstat == NFSERR_GRACE ||
634 nd->nd_repstat == NFSERR_DELAY) &&
635 error == 0)
636 (void) nfs_catnap(PZERO,
637 (int)nd->nd_repstat,
638 "nfs_close");
639 } while ((nd->nd_repstat == NFSERR_GRACE ||
640 nd->nd_repstat == NFSERR_DELAY) &&
641 error == 0 && trycnt++ < 5);
642 if (op->nfso_posixlock)
643 do_unlock = 0;
644 }
645 nfscl_freelock(lop, 0);
646 }
647 /*
648 * Do a ReleaseLockOwner.
649 * The lock owner name nfsl_owner may be used by other opens for
650 * other files but the lock_owner4 name that nfsrpc_rellockown()
651 * puts on the wire has the file handle for this file appended
652 * to it, so it can be done now.
653 */
654 (void)nfsrpc_rellockown(nmp, lp, lp->nfsl_open->nfso_fh,
655 lp->nfsl_open->nfso_fhlen, tcred, p);
656 }
657
658 /*
659 * There could be other Opens for different files on the same
660 * OpenOwner, so locking is required.
661 */
662 NFSLOCKCLSTATE();
663 nfscl_lockexcl(&op->nfso_own->nfsow_rwlock, NFSCLSTATEMUTEXPTR);
664 NFSUNLOCKCLSTATE();
665 do {
666 error = nfscl_tryclose(op, tcred, nmp, p);
667 if (error == NFSERR_GRACE)
668 (void) nfs_catnap(PZERO, error, "nfs_close");
669 } while (error == NFSERR_GRACE);
670 NFSLOCKCLSTATE();
671 nfscl_lockunlock(&op->nfso_own->nfsow_rwlock);
672
673 LIST_FOREACH_SAFE(lp, &op->nfso_lock, nfsl_list, nlp)
674 nfscl_freelockowner(lp, 0);
675 nfscl_freeopen(op, 0);
676 NFSUNLOCKCLSTATE();
677 NFSFREECRED(tcred);
678}
679
680/*
681 * The actual Close RPC.
682 */
683APPLESTATIC int
684nfsrpc_closerpc(struct nfsrv_descript *nd, struct nfsmount *nmp,
685 struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p,
686 int syscred)
687{
688 u_int32_t *tl;
689 int error;
690
691 nfscl_reqstart(nd, NFSPROC_CLOSE, nmp, op->nfso_fh,
692 op->nfso_fhlen, NULL);
693 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
694 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
695 *tl++ = op->nfso_stateid.seqid;
696 *tl++ = op->nfso_stateid.other[0];
697 *tl++ = op->nfso_stateid.other[1];
698 *tl = op->nfso_stateid.other[2];
699 if (syscred)
700 nd->nd_flag |= ND_USEGSSNAME;
701 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
702 NFS_PROG, NFS_VER4, NULL, 1, NULL);
703 if (error)
704 return (error);
705 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
706 if (nd->nd_repstat == 0)
707 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
708 error = nd->nd_repstat;
709 if (error == NFSERR_STALESTATEID)
710 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
711nfsmout:
712 mbuf_freem(nd->nd_mrep);
713 return (error);
714}
715
716/*
717 * V4 Open Confirm RPC.
718 */
719APPLESTATIC int
720nfsrpc_openconfirm(vnode_t vp, u_int8_t *nfhp, int fhlen,
721 struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p)
722{
723 u_int32_t *tl;
724 struct nfsrv_descript nfsd, *nd = &nfsd;
725 int error;
726
727 nfscl_reqstart(nd, NFSPROC_OPENCONFIRM, VFSTONFS(vnode_mount(vp)),
728 nfhp, fhlen, NULL);
729 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
730 *tl++ = op->nfso_stateid.seqid;
731 *tl++ = op->nfso_stateid.other[0];
732 *tl++ = op->nfso_stateid.other[1];
733 *tl++ = op->nfso_stateid.other[2];
734 *tl = txdr_unsigned(op->nfso_own->nfsow_seqid);
735 error = nfscl_request(nd, vp, p, cred, NULL);
736 if (error)
737 return (error);
738 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
739 if (!nd->nd_repstat) {
740 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
741 op->nfso_stateid.seqid = *tl++;
742 op->nfso_stateid.other[0] = *tl++;
743 op->nfso_stateid.other[1] = *tl++;
744 op->nfso_stateid.other[2] = *tl;
745 }
746 error = nd->nd_repstat;
747 if (error == NFSERR_STALESTATEID)
748 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
749nfsmout:
750 mbuf_freem(nd->nd_mrep);
751 return (error);
752}
753
754/*
755 * Do the setclientid and setclientid confirm RPCs. Called from nfs_statfs()
756 * when a mount has just occurred and when the server replies NFSERR_EXPIRED.
757 */
758APPLESTATIC int
759nfsrpc_setclient(struct nfsmount *nmp, struct nfsclclient *clp,
760 struct ucred *cred, NFSPROC_T *p)
761{
762 u_int32_t *tl;
763 struct nfsrv_descript nfsd;
764 struct nfsrv_descript *nd = &nfsd;
765 nfsattrbit_t attrbits;
766 u_int8_t *cp = NULL, *cp2, addr[INET6_ADDRSTRLEN + 9];
767 u_short port;
768 int error, isinet6 = 0, callblen;
769 nfsquad_t confirm;
770 u_int32_t lease;
771 static u_int32_t rev = 0;
772
773 if (nfsboottime.tv_sec == 0)
774 NFSSETBOOTTIME(nfsboottime);
775 nfscl_reqstart(nd, NFSPROC_SETCLIENTID, nmp, NULL, 0, NULL);
776 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
777 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
778 *tl = txdr_unsigned(rev++);
779 (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen);
780
781 /*
782 * set up the callback address
783 */
784 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
785 *tl = txdr_unsigned(NFS_CALLBCKPROG);
786 callblen = strlen(nfsv4_callbackaddr);
787 if (callblen == 0)
788 cp = nfscl_getmyip(nmp, &isinet6);
789 if (nfscl_enablecallb && nfs_numnfscbd > 0 &&
790 (callblen > 0 || cp != NULL)) {
791 port = htons(nfsv4_cbport);
792 cp2 = (u_int8_t *)&port;
793#ifdef INET6
794 if ((callblen > 0 &&
795 strchr(nfsv4_callbackaddr, ':')) || isinet6) {
796 char ip6buf[INET6_ADDRSTRLEN], *ip6add;
797
798 (void) nfsm_strtom(nd, "tcp6", 4);
799 if (callblen == 0) {
800 ip6_sprintf(ip6buf, (struct in6_addr *)cp);
801 ip6add = ip6buf;
802 } else {
803 ip6add = nfsv4_callbackaddr;
804 }
805 snprintf(addr, INET6_ADDRSTRLEN + 9, "%s.%d.%d",
806 ip6add, cp2[0], cp2[1]);
807 } else
808#endif
809 {
810 (void) nfsm_strtom(nd, "tcp", 3);
811 if (callblen == 0)
812 snprintf(addr, INET6_ADDRSTRLEN + 9,
813 "%d.%d.%d.%d.%d.%d", cp[0], cp[1],
814 cp[2], cp[3], cp2[0], cp2[1]);
815 else
816 snprintf(addr, INET6_ADDRSTRLEN + 9,
817 "%s.%d.%d", nfsv4_callbackaddr,
818 cp2[0], cp2[1]);
819 }
820 (void) nfsm_strtom(nd, addr, strlen(addr));
821 } else {
822 (void) nfsm_strtom(nd, "tcp", 3);
823 (void) nfsm_strtom(nd, "0.0.0.0.0.0", 11);
824 }
825 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
826 *tl = txdr_unsigned(clp->nfsc_cbident);
827 nd->nd_flag |= ND_USEGSSNAME;
828 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
829 NFS_PROG, NFS_VER4, NULL, 1, NULL);
830 if (error)
831 return (error);
832 if (nd->nd_repstat == 0) {
833 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
834 clp->nfsc_clientid.lval[0] = *tl++;
835 clp->nfsc_clientid.lval[1] = *tl++;
836 confirm.lval[0] = *tl++;
837 confirm.lval[1] = *tl;
838 mbuf_freem(nd->nd_mrep);
839 nd->nd_mrep = NULL;
840
841 /*
842 * and confirm it.
843 */
844 nfscl_reqstart(nd, NFSPROC_SETCLIENTIDCFRM, nmp, NULL, 0, NULL);
845 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
846 *tl++ = clp->nfsc_clientid.lval[0];
847 *tl++ = clp->nfsc_clientid.lval[1];
848 *tl++ = confirm.lval[0];
849 *tl = confirm.lval[1];
850 nd->nd_flag |= ND_USEGSSNAME;
851 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p,
852 cred, NFS_PROG, NFS_VER4, NULL, 1, NULL);
853 if (error)
854 return (error);
855 mbuf_freem(nd->nd_mrep);
856 nd->nd_mrep = NULL;
857 if (nd->nd_repstat == 0) {
858 nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, nmp->nm_fh,
859 nmp->nm_fhsize, NULL);
860 NFSZERO_ATTRBIT(&attrbits);
861 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME);
862 (void) nfsrv_putattrbit(nd, &attrbits);
863 nd->nd_flag |= ND_USEGSSNAME;
864 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p,
865 cred, NFS_PROG, NFS_VER4, NULL, 1, NULL);
866 if (error)
867 return (error);
868 if (nd->nd_repstat == 0) {
869 error = nfsv4_loadattr(nd, NULL, NULL, NULL, NULL, 0, NULL,
870 NULL, NULL, NULL, NULL, 0, NULL, &lease, NULL, p, cred);
871 if (error)
872 goto nfsmout;
873 clp->nfsc_renew = NFSCL_RENEW(lease);
874 clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew;
875 clp->nfsc_clientidrev++;
876 if (clp->nfsc_clientidrev == 0)
877 clp->nfsc_clientidrev++;
878 }
879 }
880 }
881 error = nd->nd_repstat;
882nfsmout:
883 mbuf_freem(nd->nd_mrep);
884 return (error);
885}
886
887/*
888 * nfs getattr call.
889 */
890APPLESTATIC int
891nfsrpc_getattr(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
892 struct nfsvattr *nap, void *stuff)
893{
894 struct nfsrv_descript nfsd, *nd = &nfsd;
895 int error;
896 nfsattrbit_t attrbits;
897
898 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
899 if (nd->nd_flag & ND_NFSV4) {
900 NFSGETATTR_ATTRBIT(&attrbits);
901 (void) nfsrv_putattrbit(nd, &attrbits);
902 }
903 error = nfscl_request(nd, vp, p, cred, stuff);
904 if (error)
905 return (error);
906 if (!nd->nd_repstat)
907 error = nfsm_loadattr(nd, nap);
908 else
909 error = nd->nd_repstat;
910 mbuf_freem(nd->nd_mrep);
911 return (error);
912}
913
914/*
915 * nfs getattr call with non-vnode arguemnts.
916 */
917APPLESTATIC int
918nfsrpc_getattrnovp(struct nfsmount *nmp, u_int8_t *fhp, int fhlen, int syscred,
919 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, u_int64_t *xidp)
920{
921 struct nfsrv_descript nfsd, *nd = &nfsd;
922 int error, vers = NFS_VER2;
923 nfsattrbit_t attrbits;
924
925 nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, fhp, fhlen, NULL);
926 if (nd->nd_flag & ND_NFSV4) {
927 vers = NFS_VER4;
928 NFSGETATTR_ATTRBIT(&attrbits);
929 (void) nfsrv_putattrbit(nd, &attrbits);
930 } else if (nd->nd_flag & ND_NFSV3) {
931 vers = NFS_VER3;
932 }
933 if (syscred)
934 nd->nd_flag |= ND_USEGSSNAME;
935 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
936 NFS_PROG, vers, NULL, 1, xidp);
937 if (error)
938 return (error);
939 if (!nd->nd_repstat)
940 error = nfsm_loadattr(nd, nap);
941 else
942 error = nd->nd_repstat;
943 mbuf_freem(nd->nd_mrep);
944 return (error);
945}
946
947/*
948 * Do an nfs setattr operation.
949 */
950APPLESTATIC int
951nfsrpc_setattr(vnode_t vp, struct vattr *vap, NFSACL_T *aclp,
952 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *rnap, int *attrflagp,
953 void *stuff)
954{
955 int error, expireret = 0, openerr, retrycnt;
956 u_int32_t clidrev = 0, mode;
957 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
958 struct nfsfh *nfhp;
959 nfsv4stateid_t stateid;
960 void *lckp;
961
962 if (nmp->nm_clp != NULL)
963 clidrev = nmp->nm_clp->nfsc_clientidrev;
964 if (vap != NULL && NFSATTRISSET(u_quad_t, vap, va_size))
965 mode = NFSV4OPEN_ACCESSWRITE;
966 else
967 mode = NFSV4OPEN_ACCESSREAD;
968 retrycnt = 0;
969 do {
970 lckp = NULL;
971 openerr = 1;
972 if (NFSHASNFSV4(nmp)) {
973 nfhp = VTONFS(vp)->n_fhp;
974 error = nfscl_getstateid(vp, nfhp->nfh_fh,
975 nfhp->nfh_len, mode, cred, p, &stateid, &lckp);
976 if (error && vnode_vtype(vp) == VREG &&
977 (mode == NFSV4OPEN_ACCESSWRITE ||
978 nfstest_openallsetattr)) {
979 /*
980 * No Open stateid, so try and open the file
981 * now.
982 */
983 if (mode == NFSV4OPEN_ACCESSWRITE)
984 openerr = nfsrpc_open(vp, FWRITE, cred,
985 p);
986 else
987 openerr = nfsrpc_open(vp, FREAD, cred,
988 p);
989 if (!openerr)
990 (void) nfscl_getstateid(vp,
991 nfhp->nfh_fh, nfhp->nfh_len,
992 mode, cred, p, &stateid, &lckp);
993 }
994 }
995 if (vap != NULL)
996 error = nfsrpc_setattrrpc(vp, vap, &stateid, cred, p,
997 rnap, attrflagp, stuff);
998 else
999 error = nfsrpc_setaclrpc(vp, cred, p, aclp, &stateid,
1000 stuff);
1001 if (error == NFSERR_STALESTATEID)
1002 nfscl_initiate_recovery(nmp->nm_clp);
1003 if (lckp != NULL)
1004 nfscl_lockderef(lckp);
1005 if (!openerr)
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);
1014 }
1015 retrycnt++;
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)
1022 error = EIO;
1023 return (error);
1024}
1025
1026static int
1027nfsrpc_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)
1030{
1031 u_int32_t *tl;
1032 struct nfsrv_descript nfsd, *nd = &nfsd;
1033 int error;
1034 nfsattrbit_t attrbits;
1035
1036 *attrflagp = 0;
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);
1044 *tl = newnfs_false;
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);
1050 }
1051 error = nfscl_request(nd, vp, p, cred, stuff);
1052 if (error)
1053 return (error);
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;
1063 return (error);
1064}
1065
1066/*
1067 * nfs lookup rpc
1068 */
1069APPLESTATIC int
1070nfsrpc_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)
1073{
1074 u_int32_t *tl;
1075 struct nfsrv_descript nfsd, *nd = &nfsd;
1076 struct nfsmount *nmp;
1077 struct nfsnode *np;
1078 struct nfsfh *nfhp;
1079 nfsattrbit_t attrbits;
1080 int error = 0, lookupp = 0;
1081
1082 *attrflagp = 0;
1083 *dattrflagp = 0;
1084 if (vnode_vtype(dvp) != VDIR)
1085 return (ENOTDIR);
1086 nmp = VFSTONFS(vnode_mount(dvp));
1087 if (len > NFS_MAXNAMLEN)
1088 return (ENAMETOOLONG);
1089 if (NFSHASNFSV4(nmp) && len == 1 &&
1090 name[0] == '.') {
1091 /*
1092 * Just return the current dir's fh.
1093 */
1094 np = VTONFS(dvp);
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);
1099 *nfhpp = nfhp;
1100 return (0);
1101 }
1102 if (NFSHASNFSV4(nmp) && len == 2 &&
1103 name[0] == '.' && name[1] == '.') {
1104 lookupp = 1;
1105 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, dvp);
1106 } else {
1107 NFSCL_REQSTART(nd, NFSPROC_LOOKUP, dvp);
1108 (void) nfsm_strtom(nd, name, len);
1109 }
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);
1116 }
1117 error = nfscl_request(nd, dvp, p, cred, stuff);
1118 if (error)
1119 return (error);
1120 if (nd->nd_repstat) {
1121 /*
1122 * When an NFSv4 Lookupp returns ENOENT, it means that
1123 * the lookup is at the root of an fs, so return this dir.
1124 */
1125 if (nd->nd_repstat == NFSERR_NOENT && lookupp) {
1126 np = VTONFS(dvp);
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);
1131 *nfhpp = nfhp;
1132 mbuf_freem(nd->nd_mrep);
1133 return (0);
1134 }
1135 if (nd->nd_flag & ND_NFSV3)
1136 error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff);
1137 goto nfsmout;
1138 }
1139 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
1140 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1141 if (*(tl + 1)) {
1142 nd->nd_flag |= ND_NOMOREDATA;
1143 goto nfsmout;
1144 }
1145 }
1146 error = nfsm_getfh(nd, nfhpp);
1147 if (error)
1148 goto nfsmout;
1149
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);
1153nfsmout:
1154 mbuf_freem(nd->nd_mrep);
1155 if (!error && nd->nd_repstat)
1156 error = nd->nd_repstat;
1157 return (error);
1158}
1159
1160/*
1161 * Do a readlink rpc.
1162 */
1163APPLESTATIC int
1164nfsrpc_readlink(vnode_t vp, struct uio *uiop, struct ucred *cred,
1165 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
1166{
1167 u_int32_t *tl;
1168 struct nfsrv_descript nfsd, *nd = &nfsd;
1169 struct nfsnode *np = VTONFS(vp);
1170 nfsattrbit_t attrbits;
1171 int error, len, cangetattr = 1;
1172
1173 *attrflagp = 0;
1174 NFSCL_REQSTART(nd, NFSPROC_READLINK, vp);
1175 if (nd->nd_flag & ND_NFSV4) {
1176 /*
1177 * And do a Getattr op.
1178 */
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);
1183 }
1184 error = nfscl_request(nd, vp, p, cred, stuff);
1185 if (error)
1186 return (error);
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);
1191 /*
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?
1196 */
1197 if (len == NFS_MAXPATHLEN) {
1198 NFSLOCKNODE(np);
1199 if (np->n_size > 0 && np->n_size < NFS_MAXPATHLEN) {
1200 len = np->n_size;
1201 cangetattr = 0;
1202 }
1203 NFSUNLOCKNODE(np);
1204 }
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);
1208 }
1209 if (nd->nd_repstat && !error)
1210 error = nd->nd_repstat;
1211nfsmout:
1212 mbuf_freem(nd->nd_mrep);
1213 return (error);
1214}
1215
1216/*
1217 * Read operation.
1218 */
1219APPLESTATIC int
1220nfsrpc_read(vnode_t vp, struct uio *uiop, struct ucred *cred,
1221 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
1222{
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;
1230 void *lckp;
1231
1232 if (nmp->nm_clp != NULL)
1233 clidrev = nmp->nm_clp->nfsc_clientidrev;
1234 newcred = cred;
1235 if (NFSHASNFSV4(nmp)) {
1236 nfhp = np->n_fhp;
1237 newcred = NFSNEWCRED(cred);
1238 }
1239 retrycnt = 0;
1240 do {
1241 lckp = NULL;
1242 if (NFSHASNFSV4(nmp))
1243 (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
1244 NFSV4OPEN_ACCESSREAD, newcred, p, &stateid, &lckp);
1245 error = nfsrpc_readrpc(vp, uiop, newcred, &stateid, p, nap,
1246 attrflagp, stuff);
1247 if (error == NFSERR_STALESTATEID)
1248 nfscl_initiate_recovery(nmp->nm_clp);
1249 if (lckp != NULL)
1250 nfscl_lockderef(lckp);
1251 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1252 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1253 error == NFSERR_OLDSTATEID) {
1254 (void) nfs_catnap(PZERO, error, "nfs_read");
1255 } else if ((error == NFSERR_EXPIRED ||
1256 error == NFSERR_BADSTATEID) && clidrev != 0) {
1257 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1258 }
1259 retrycnt++;
1260 } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1261 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1262 (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
1263 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1264 expireret == 0 && clidrev != 0 && retrycnt < 4));
1265 if (error && retrycnt >= 4)
1266 error = EIO;
1267 if (NFSHASNFSV4(nmp))
1268 NFSFREECRED(newcred);
1269 return (error);
1270}
1271
1272/*
1273 * The actual read RPC.
1274 */
1275static int
1276nfsrpc_readrpc(vnode_t vp, struct uio *uiop, struct ucred *cred,
1277 nfsv4stateid_t *stateidp, NFSPROC_T *p, struct nfsvattr *nap,
1278 int *attrflagp, void *stuff)
1279{
1280 u_int32_t *tl;
1281 int error = 0, len, retlen, tsiz, eof = 0;
1282 struct nfsrv_descript nfsd;
1283 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1284 struct nfsrv_descript *nd = &nfsd;
1285 int rsize;
1286 off_t tmp_off;
1287
1288 *attrflagp = 0;
1289 tsiz = uio_uio_resid(uiop);
1290 tmp_off = uiop->uio_offset + tsiz;
1291 NFSLOCKMNT(nmp);
1292 if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) {
1293 NFSUNLOCKMNT(nmp);
1294 return (EFBIG);
1295 }
1296 rsize = nmp->nm_rsize;
1297 NFSUNLOCKMNT(nmp);
1298 nd->nd_mrep = NULL;
1299 while (tsiz > 0) {
1300 *attrflagp = 0;
1301 len = (tsiz > rsize) ? rsize : tsiz;
1302 NFSCL_REQSTART(nd, NFSPROC_READ, vp);
1303 if (nd->nd_flag & ND_NFSV4)
1304 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
1305 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED * 3);
1306 if (nd->nd_flag & ND_NFSV2) {
1307 *tl++ = txdr_unsigned(uiop->uio_offset);
1308 *tl++ = txdr_unsigned(len);
1309 *tl = 0;
1310 } else {
1311 txdr_hyper(uiop->uio_offset, tl);
1312 *(tl + 2) = txdr_unsigned(len);
1313 }
1314 /*
1315 * Since I can't do a Getattr for NFSv4 for Write, there
1316 * doesn't seem any point in doing one here, either.
1317 * (See the comment in nfsrpc_writerpc() for more info.)
1318 */
1319 error = nfscl_request(nd, vp, p, cred, stuff);
1320 if (error)
1321 return (error);
1322 if (nd->nd_flag & ND_NFSV3) {
1323 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
1324 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
1325 error = nfsm_loadattr(nd, nap);
1326 if (!error)
1327 *attrflagp = 1;
1328 }
1329 if (nd->nd_repstat || error) {
1330 if (!error)
1331 error = nd->nd_repstat;
1332 goto nfsmout;
1333 }
1334 if (nd->nd_flag & ND_NFSV3) {
1335 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1336 eof = fxdr_unsigned(int, *(tl + 1));
1337 } else if (nd->nd_flag & ND_NFSV4) {
1338 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1339 eof = fxdr_unsigned(int, *tl);
1340 }
1341 NFSM_STRSIZ(retlen, rsize);
1342 error = nfsm_mbufuio(nd, uiop, retlen);
1343 if (error)
1344 goto nfsmout;
1345 mbuf_freem(nd->nd_mrep);
1346 nd->nd_mrep = NULL;
1347 tsiz -= retlen;
1348 if (!(nd->nd_flag & ND_NFSV2)) {
1349 if (eof || retlen == 0)
1350 tsiz = 0;
1351 } else if (retlen < len)
1352 tsiz = 0;
1353 }
1354 return (0);
1355nfsmout:
1356 if (nd->nd_mrep != NULL)
1357 mbuf_freem(nd->nd_mrep);
1358 return (error);
1359}
1360
1361/*
1362 * nfs write operation
1363 * When called_from_strategy != 0, it should return EIO for an error that
1364 * indicates recovery is in progress, so that the buffer will be left
1365 * dirty and be written back to the server later. If it loops around,
1366 * the recovery thread could get stuck waiting for the buffer and recovery
1367 * will then deadlock.
1368 */
1369APPLESTATIC int
1370nfsrpc_write(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
1371 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
1372 void *stuff, int called_from_strategy)
1373{
1374 int error, expireret = 0, retrycnt, nostateid;
1375 u_int32_t clidrev = 0;
1376 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1377 struct nfsnode *np = VTONFS(vp);
1378 struct ucred *newcred;
1379 struct nfsfh *nfhp = NULL;
1380 nfsv4stateid_t stateid;
1381 void *lckp;
1382
1383 *must_commit = 0;
1384 if (nmp->nm_clp != NULL)
1385 clidrev = nmp->nm_clp->nfsc_clientidrev;
1386 newcred = cred;
1387 if (NFSHASNFSV4(nmp)) {
1388 newcred = NFSNEWCRED(cred);
1389 nfhp = np->n_fhp;
1390 }
1391 retrycnt = 0;
1392 do {
1393 lckp = NULL;
1394 nostateid = 0;
1395 if (NFSHASNFSV4(nmp)) {
1396 (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
1397 NFSV4OPEN_ACCESSWRITE, newcred, p, &stateid, &lckp);
1398 if (stateid.other[0] == 0 && stateid.other[1] == 0 &&
1399 stateid.other[2] == 0) {
1400 nostateid = 1;
1401 printf("stateid0 in write\n");
1402 }
1403 }
1404
1405 /*
1406 * If there is no stateid for NFSv4, it means this is an
1407 * extraneous write after close. Basically a poorly
1408 * implemented buffer cache. Just don't do the write.
1409 */
1410 if (nostateid)
1411 error = 0;
1412 else
1413 error = nfsrpc_writerpc(vp, uiop, iomode, must_commit,
1414 newcred, &stateid, p, nap, attrflagp, stuff);
1415 if (error == NFSERR_STALESTATEID)
1416 nfscl_initiate_recovery(nmp->nm_clp);
1417 if (lckp != NULL)
1418 nfscl_lockderef(lckp);
1419 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1420 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1421 error == NFSERR_OLDSTATEID) {
1422 (void) nfs_catnap(PZERO, error, "nfs_write");
1423 } else if ((error == NFSERR_EXPIRED ||
1424 error == NFSERR_BADSTATEID) && clidrev != 0) {
1425 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1426 }
1427 retrycnt++;
1428 } while (error == NFSERR_GRACE || error == NFSERR_DELAY ||
1429 ((error == NFSERR_STALESTATEID ||
1430 error == NFSERR_STALEDONTRECOVER) && called_from_strategy == 0) ||
1431 (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
1432 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1433 expireret == 0 && clidrev != 0 && retrycnt < 4));
1434 if (error != 0 && (retrycnt >= 4 ||
1435 ((error == NFSERR_STALESTATEID ||
1436 error == NFSERR_STALEDONTRECOVER) && called_from_strategy != 0)))
1437 error = EIO;
1438 if (NFSHASNFSV4(nmp))
1439 NFSFREECRED(newcred);
1440 return (error);
1441}
1442
1443/*
1444 * The actual write RPC.
1445 */
1446static int
1447nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode,
1448 int *must_commit, struct ucred *cred, nfsv4stateid_t *stateidp,
1449 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
1450{
1451 u_int32_t *tl;
1452 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1453 struct nfsnode *np = VTONFS(vp);
1454 int error = 0, len, tsiz, rlen, commit, committed = NFSWRITE_FILESYNC;
1455 int wccflag = 0, wsize;
1456 int32_t backup;
1457 struct nfsrv_descript nfsd;
1458 struct nfsrv_descript *nd = &nfsd;
1459 nfsattrbit_t attrbits;
1460 off_t tmp_off;
1461
1462 KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1"));
1463 *attrflagp = 0;
1464 tsiz = uio_uio_resid(uiop);
1465 tmp_off = uiop->uio_offset + tsiz;
1466 NFSLOCKMNT(nmp);
1467 if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) {
1468 NFSUNLOCKMNT(nmp);
1469 return (EFBIG);
1470 }
1471 wsize = nmp->nm_wsize;
1472 NFSUNLOCKMNT(nmp);
1473 nd->nd_mrep = NULL; /* NFSv2 sometimes does a write with */
1474 nd->nd_repstat = 0; /* uio_resid == 0, so the while is not done */
1475 while (tsiz > 0) {
1476 *attrflagp = 0;
1477 len = (tsiz > wsize) ? wsize : tsiz;
1478 NFSCL_REQSTART(nd, NFSPROC_WRITE, vp);
1479 if (nd->nd_flag & ND_NFSV4) {
1480 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
1481 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+2*NFSX_UNSIGNED);
1482 txdr_hyper(uiop->uio_offset, tl);
1483 tl += 2;
1484 *tl++ = txdr_unsigned(*iomode);
1485 *tl = txdr_unsigned(len);
1486 } else if (nd->nd_flag & ND_NFSV3) {
1487 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+3*NFSX_UNSIGNED);
1488 txdr_hyper(uiop->uio_offset, tl);
1489 tl += 2;
1490 *tl++ = txdr_unsigned(len);
1491 *tl++ = txdr_unsigned(*iomode);
1492 *tl = txdr_unsigned(len);
1493 } else {
1494 u_int32_t x;
1495
1496 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1497 /*
1498 * Not sure why someone changed this, since the
1499 * RFC clearly states that "beginoffset" and
1500 * "totalcount" are ignored, but it wouldn't
1501 * surprise me if there's a busted server out there.
1502 */
1503 /* Set both "begin" and "current" to non-garbage. */
1504 x = txdr_unsigned((u_int32_t)uiop->uio_offset);
1505 *tl++ = x; /* "begin offset" */
1506 *tl++ = x; /* "current offset" */
1507 x = txdr_unsigned(len);
1508 *tl++ = x; /* total to this offset */
1509 *tl = x; /* size of this write */
1510
1511 }
1512 nfsm_uiombuf(nd, uiop, len);
1513 /*
1514 * Although it is tempting to do a normal Getattr Op in the
1515 * NFSv4 compound, the result can be a nearly hung client
1516 * system if the Getattr asks for Owner and/or OwnerGroup.
1517 * It occurs when the client can't map either the Owner or
1518 * Owner_group name in the Getattr reply to a uid/gid. When
1519 * there is a cache miss, the kernel does an upcall to the
1520 * nfsuserd. Then, it can try and read the local /etc/passwd
1521 * or /etc/group file. It can then block in getnewbuf(),
1522 * waiting for dirty writes to be pushed to the NFS server.
1523 * The only reason this doesn't result in a complete
1524 * deadlock, is that the upcall times out and allows
1525 * the write to complete. However, progress is so slow
1526 * that it might just as well be deadlocked.
1527 * As such, we get the rest of the attributes, but not
1528 * Owner or Owner_group.
1529 * nb: nfscl_loadattrcache() needs to be told that these
1530 * partial attributes from a write rpc are being
1531 * passed in, via a argument flag.
1532 */
1533 if (nd->nd_flag & ND_NFSV4) {
1534 NFSWRITEGETATTR_ATTRBIT(&attrbits);
1535 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1536 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1537 (void) nfsrv_putattrbit(nd, &attrbits);
1538 }
1539 error = nfscl_request(nd, vp, p, cred, stuff);
1540 if (error)
1541 return (error);
1542 if (nd->nd_repstat) {
1543 /*
1544 * In case the rpc gets retried, roll
1545 * the uio fileds changed by nfsm_uiombuf()
1546 * back.
1547 */
1548 uiop->uio_offset -= len;
1549 uio_uio_resid_add(uiop, len);
1550 uio_iov_base_add(uiop, -len);
1551 uio_iov_len_add(uiop, len);
1552 }
1553 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1554 error = nfscl_wcc_data(nd, vp, nap, attrflagp,
1555 &wccflag, stuff);
1556 if (error)
1557 goto nfsmout;
1558 }
1559 if (!nd->nd_repstat) {
1560 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1561 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED
1562 + NFSX_VERF);
1563 rlen = fxdr_unsigned(int, *tl++);
1564 if (rlen == 0) {
1565 error = NFSERR_IO;
1566 goto nfsmout;
1567 } else if (rlen < len) {
1568 backup = len - rlen;
1569 uio_iov_base_add(uiop, -(backup));
1570 uio_iov_len_add(uiop, backup);
1571 uiop->uio_offset -= backup;
1572 uio_uio_resid_add(uiop, backup);
1573 len = rlen;
1574 }
1575 commit = fxdr_unsigned(int, *tl++);
1576
1577 /*
1578 * Return the lowest committment level
1579 * obtained by any of the RPCs.
1580 */
1581 if (committed == NFSWRITE_FILESYNC)
1582 committed = commit;
1583 else if (committed == NFSWRITE_DATASYNC &&
1584 commit == NFSWRITE_UNSTABLE)
1585 committed = commit;
1586 NFSLOCKMNT(nmp);
1587 if (!NFSHASWRITEVERF(nmp)) {
1588 NFSBCOPY((caddr_t)tl,
1589 (caddr_t)&nmp->nm_verf[0],
1590 NFSX_VERF);
1591 NFSSETWRITEVERF(nmp);
1592 } else if (NFSBCMP(tl, nmp->nm_verf,
1593 NFSX_VERF)) {
1594 *must_commit = 1;
1595 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
1596 }
1597 NFSUNLOCKMNT(nmp);
1598 }
1599 if (nd->nd_flag & ND_NFSV4)
1600 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1601 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV4)) {
1602 error = nfsm_loadattr(nd, nap);
1603 if (!error)
1604 *attrflagp = NFS_LATTR_NOSHRINK;
1605 }
1606 } else {
1607 error = nd->nd_repstat;
1608 }
1609 if (error)
1610 goto nfsmout;
1611 NFSWRITERPC_SETTIME(wccflag, np, (nd->nd_flag & ND_NFSV4));
1612 mbuf_freem(nd->nd_mrep);
1613 nd->nd_mrep = NULL;
1614 tsiz -= len;
1615 }
1616nfsmout:
1617 if (nd->nd_mrep != NULL)
1618 mbuf_freem(nd->nd_mrep);
1619 *iomode = committed;
1620 if (nd->nd_repstat && !error)
1621 error = nd->nd_repstat;
1622 return (error);
1623}
1624
1625/*
1626 * nfs mknod rpc
1627 * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the
1628 * mode set to specify the file type and the size field for rdev.
1629 */
1630APPLESTATIC int
1631nfsrpc_mknod(vnode_t dvp, char *name, int namelen, struct vattr *vap,
1632 u_int32_t rdev, enum vtype vtyp, struct ucred *cred, NFSPROC_T *p,
1633 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
1634 int *attrflagp, int *dattrflagp, void *dstuff)
1635{
1636 u_int32_t *tl;
1637 int error = 0;
1638 struct nfsrv_descript nfsd, *nd = &nfsd;
1639 nfsattrbit_t attrbits;
1640
1641 *nfhpp = NULL;
1642 *attrflagp = 0;
1643 *dattrflagp = 0;
1644 if (namelen > NFS_MAXNAMLEN)
1645 return (ENAMETOOLONG);
1646 NFSCL_REQSTART(nd, NFSPROC_MKNOD, dvp);
1647 if (nd->nd_flag & ND_NFSV4) {
1648 if (vtyp == VBLK || vtyp == VCHR) {
1649 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1650 *tl++ = vtonfsv34_type(vtyp);
1651 *tl++ = txdr_unsigned(NFSMAJOR(rdev));
1652 *tl = txdr_unsigned(NFSMINOR(rdev));
1653 } else {
1654 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1655 *tl = vtonfsv34_type(vtyp);
1656 }
1657 }
1658 (void) nfsm_strtom(nd, name, namelen);
1659 if (nd->nd_flag & ND_NFSV3) {
1660 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1661 *tl = vtonfsv34_type(vtyp);
1662 }
1663 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
1664 nfscl_fillsattr(nd, vap, dvp, 0, 0);
1665 if ((nd->nd_flag & ND_NFSV3) &&
1666 (vtyp == VCHR || vtyp == VBLK)) {
1667 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1668 *tl++ = txdr_unsigned(NFSMAJOR(rdev));
1669 *tl = txdr_unsigned(NFSMINOR(rdev));
1670 }
1671 if (nd->nd_flag & ND_NFSV4) {
1672 NFSGETATTR_ATTRBIT(&attrbits);
1673 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1674 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
1675 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1676 (void) nfsrv_putattrbit(nd, &attrbits);
1677 }
1678 if (nd->nd_flag & ND_NFSV2)
1679 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZERDEV, rdev);
1680 error = nfscl_request(nd, dvp, p, cred, dstuff);
1681 if (error)
1682 return (error);
1683 if (nd->nd_flag & ND_NFSV4)
1684 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
1685 if (!nd->nd_repstat) {
1686 if (nd->nd_flag & ND_NFSV4) {
1687 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1688 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1689 if (error)
1690 goto nfsmout;
1691 }
1692 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
1693 if (error)
1694 goto nfsmout;
1695 }
1696 if (nd->nd_flag & ND_NFSV3)
1697 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
1698 if (!error && nd->nd_repstat)
1699 error = nd->nd_repstat;
1700nfsmout:
1701 mbuf_freem(nd->nd_mrep);
1702 return (error);
1703}
1704
1705/*
1706 * nfs file create call
1707 * Mostly just call the approriate routine. (I separated out v4, so that
1708 * error recovery wouldn't be as difficult.)
1709 */
1710APPLESTATIC int
1711nfsrpc_create(vnode_t dvp, char *name, int namelen, struct vattr *vap,
1712 nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p,
1713 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
1714 int *attrflagp, int *dattrflagp, void *dstuff)
1715{
1716 int error = 0, newone, expireret = 0, retrycnt, unlocked;
1717 struct nfsclowner *owp;
1718 struct nfscldeleg *dp;
1719 struct nfsmount *nmp = VFSTONFS(vnode_mount(dvp));
1720 u_int32_t clidrev;
1721
1722 if (NFSHASNFSV4(nmp)) {
1723 retrycnt = 0;
1724 do {
1725 dp = NULL;
1726 error = nfscl_open(dvp, NULL, 0, (NFSV4OPEN_ACCESSWRITE |
1727 NFSV4OPEN_ACCESSREAD), 0, cred, p, &owp, NULL, &newone,
1728 NULL, 1);
1729 if (error)
1730 return (error);
1731 if (nmp->nm_clp != NULL)
1732 clidrev = nmp->nm_clp->nfsc_clientidrev;
1733 else
1734 clidrev = 0;
1735 error = nfsrpc_createv4(dvp, name, namelen, vap, cverf, fmode,
1736 owp, &dp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp,
1737 dstuff, &unlocked);
1738 /*
1739 * There is no need to invalidate cached attributes here,
1740 * since new post-delegation issue attributes are always
1741 * returned by nfsrpc_createv4() and these will update the
1742 * attribute cache.
1743 */
1744 if (dp != NULL)
1745 (void) nfscl_deleg(nmp->nm_mountp, owp->nfsow_clp,
1746 (*nfhpp)->nfh_fh, (*nfhpp)->nfh_len, cred, p, &dp);
1747 nfscl_ownerrelease(owp, error, newone, unlocked);
1748 if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
1749 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY) {
1750 (void) nfs_catnap(PZERO, error, "nfs_open");
1751 } else if ((error == NFSERR_EXPIRED ||
1752 error == NFSERR_BADSTATEID) && clidrev != 0) {
1753 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1754 retrycnt++;
1755 }
1756 } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
1757 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1758 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1759 expireret == 0 && clidrev != 0 && retrycnt < 4));
1760 if (error && retrycnt >= 4)
1761 error = EIO;
1762 } else {
1763 error = nfsrpc_createv23(dvp, name, namelen, vap, cverf,
1764 fmode, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp,
1765 dstuff);
1766 }
1767 return (error);
1768}
1769
1770/*
1771 * The create rpc for v2 and 3.
1772 */
1773static int
1774nfsrpc_createv23(vnode_t dvp, char *name, int namelen, struct vattr *vap,
1775 nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p,
1776 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
1777 int *attrflagp, int *dattrflagp, void *dstuff)
1778{
1779 u_int32_t *tl;
1780 int error = 0;
1781 struct nfsrv_descript nfsd, *nd = &nfsd;
1782
1783 *nfhpp = NULL;
1784 *attrflagp = 0;
1785 *dattrflagp = 0;
1786 if (namelen > NFS_MAXNAMLEN)
1787 return (ENAMETOOLONG);
1788 NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp);
1789 (void) nfsm_strtom(nd, name, namelen);
1790 if (nd->nd_flag & ND_NFSV3) {
1791 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1792 if (fmode & O_EXCL) {
1793 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE);
1794 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
1795 *tl++ = cverf.lval[0];
1796 *tl = cverf.lval[1];
1797 } else {
1798 *tl = txdr_unsigned(NFSCREATE_UNCHECKED);
1799 nfscl_fillsattr(nd, vap, dvp, 0, 0);
1800 }
1801 } else {
1802 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZE0, 0);
1803 }
1804 error = nfscl_request(nd, dvp, p, cred, dstuff);
1805 if (error)
1806 return (error);
1807 if (nd->nd_repstat == 0) {
1808 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
1809 if (error)
1810 goto nfsmout;
1811 }
1812 if (nd->nd_flag & ND_NFSV3)
1813 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
1814 if (nd->nd_repstat != 0 && error == 0)
1815 error = nd->nd_repstat;
1816nfsmout:
1817 mbuf_freem(nd->nd_mrep);
1818 return (error);
1819}
1820
1821static int
1822nfsrpc_createv4(vnode_t dvp, char *name, int namelen, struct vattr *vap,
1823 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp,
1824 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
1825 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
1826 int *dattrflagp, void *dstuff, int *unlockedp)
1827{
1828 u_int32_t *tl;
1829 int error = 0, deleg, newone, ret, acesize, limitby;
1830 struct nfsrv_descript nfsd, *nd = &nfsd;
1831 struct nfsclopen *op;
1832 struct nfscldeleg *dp = NULL;
1833 struct nfsnode *np;
1834 struct nfsfh *nfhp;
1835 nfsattrbit_t attrbits;
1836 nfsv4stateid_t stateid;
1837 u_int32_t rflags;
1838
1839 *unlockedp = 0;
1840 *nfhpp = NULL;
1841 *dpp = NULL;
1842 *attrflagp = 0;
1843 *dattrflagp = 0;
1844 if (namelen > NFS_MAXNAMLEN)
1845 return (ENAMETOOLONG);
1846 NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp);
1847 /*
1848 * For V4, this is actually an Open op.
1849 */
1850 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1851 *tl++ = txdr_unsigned(owp->nfsow_seqid);
1852 *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
1853 NFSV4OPEN_ACCESSREAD);
1854 *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE);
1855 *tl++ = owp->nfsow_clp->nfsc_clientid.lval[0];
1856 *tl = owp->nfsow_clp->nfsc_clientid.lval[1];
1857 (void) nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN);
1858 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1859 *tl++ = txdr_unsigned(NFSV4OPEN_CREATE);
1860 if (fmode & O_EXCL) {
1861 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE);
1862 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
1863 *tl++ = cverf.lval[0];
1864 *tl = cverf.lval[1];
1865 } else {
1866 *tl = txdr_unsigned(NFSCREATE_UNCHECKED);
1867 nfscl_fillsattr(nd, vap, dvp, 0, 0);
1868 }
1869 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1870 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
1871 (void) nfsm_strtom(nd, name, namelen);
1872 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1873 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
1874 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1875 NFSGETATTR_ATTRBIT(&attrbits);
1876 (void) nfsrv_putattrbit(nd, &attrbits);
1877 error = nfscl_request(nd, dvp, p, cred, dstuff);
1878 if (error)
1879 return (error);
1880 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
1881 if (error)
1882 goto nfsmout;
1883 NFSCL_INCRSEQID(owp->nfsow_seqid, nd);
1884 if (nd->nd_repstat == 0) {
1885 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
1886 6 * NFSX_UNSIGNED);
1887 stateid.seqid = *tl++;
1888 stateid.other[0] = *tl++;
1889 stateid.other[1] = *tl++;
1890 stateid.other[2] = *tl;
1891 rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
1892 (void) nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1893 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1894 deleg = fxdr_unsigned(int, *tl);
1895 if (deleg == NFSV4OPEN_DELEGATEREAD ||
1896 deleg == NFSV4OPEN_DELEGATEWRITE) {
1897 if (!(owp->nfsow_clp->nfsc_flags &
1898 NFSCLFLAGS_FIRSTDELEG))
1899 owp->nfsow_clp->nfsc_flags |=
1900 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
1901 MALLOC(dp, struct nfscldeleg *,
1902 sizeof (struct nfscldeleg) + NFSX_V4FHMAX,
1903 M_NFSCLDELEG, M_WAITOK);
1904 LIST_INIT(&dp->nfsdl_owner);
1905 LIST_INIT(&dp->nfsdl_lock);
1906 dp->nfsdl_clp = owp->nfsow_clp;
1907 newnfs_copyincred(cred, &dp->nfsdl_cred);
1908 nfscl_lockinit(&dp->nfsdl_rwlock);
1909 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
1910 NFSX_UNSIGNED);
1911 dp->nfsdl_stateid.seqid = *tl++;
1912 dp->nfsdl_stateid.other[0] = *tl++;
1913 dp->nfsdl_stateid.other[1] = *tl++;
1914 dp->nfsdl_stateid.other[2] = *tl++;
1915 ret = fxdr_unsigned(int, *tl);
1916 if (deleg == NFSV4OPEN_DELEGATEWRITE) {
1917 dp->nfsdl_flags = NFSCLDL_WRITE;
1918 /*
1919 * Indicates how much the file can grow.
1920 */
1921 NFSM_DISSECT(tl, u_int32_t *,
1922 3 * NFSX_UNSIGNED);
1923 limitby = fxdr_unsigned(int, *tl++);
1924 switch (limitby) {
1925 case NFSV4OPEN_LIMITSIZE:
1926 dp->nfsdl_sizelimit = fxdr_hyper(tl);
1927 break;
1928 case NFSV4OPEN_LIMITBLOCKS:
1929 dp->nfsdl_sizelimit =
1930 fxdr_unsigned(u_int64_t, *tl++);
1931 dp->nfsdl_sizelimit *=
1932 fxdr_unsigned(u_int64_t, *tl);
1933 break;
1934 default:
1935 error = NFSERR_BADXDR;
1936 goto nfsmout;
1937 };
1938 } else {
1939 dp->nfsdl_flags = NFSCLDL_READ;
1940 }
1941 if (ret)
1942 dp->nfsdl_flags |= NFSCLDL_RECALL;
1943 error = nfsrv_dissectace(nd, &dp->nfsdl_ace, &ret,
1944 &acesize, p);
1945 if (error)
1946 goto nfsmout;
1947 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
1948 error = NFSERR_BADXDR;
1949 goto nfsmout;
1950 }
1951 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
1952 if (error)
1953 goto nfsmout;
1954 if (dp != NULL && *attrflagp) {
1955 dp->nfsdl_change = nnap->na_filerev;
1956 dp->nfsdl_modtime = nnap->na_mtime;
1957 dp->nfsdl_flags |= NFSCLDL_MODTIMESET;
1958 }
1959 /*
1960 * We can now complete the Open state.
1961 */
1962 nfhp = *nfhpp;
1963 if (dp != NULL) {
1964 dp->nfsdl_fhlen = nfhp->nfh_len;
1965 NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, nfhp->nfh_len);
1966 }
1967 /*
1968 * Get an Open structure that will be
1969 * attached to the OpenOwner, acquired already.
1970 */
1971 error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len,
1972 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0,
1973 cred, p, NULL, &op, &newone, NULL, 0);
1974 if (error)
1975 goto nfsmout;
1976 op->nfso_stateid = stateid;
1977 newnfs_copyincred(cred, &op->nfso_cred);
1978 if ((rflags & NFSV4OPEN_RESULTCONFIRM)) {
1979 do {
1980 ret = nfsrpc_openconfirm(dvp, nfhp->nfh_fh,
1981 nfhp->nfh_len, op, cred, p);
1982 if (ret == NFSERR_DELAY)
1983 (void) nfs_catnap(PZERO, ret, "nfs_create");
1984 } while (ret == NFSERR_DELAY);
1985 error = ret;
1986 }
1987
1988 /*
1989 * If the server is handing out delegations, but we didn't
1990 * get one because an OpenConfirm was required, try the
1991 * Open again, to get a delegation. This is a harmless no-op,
1992 * from a server's point of view.
1993 */
1994 if ((rflags & NFSV4OPEN_RESULTCONFIRM) &&
1995 (owp->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) &&
1996 !error && dp == NULL) {
1997 np = VTONFS(dvp);
1998 do {
1999 ret = nfsrpc_openrpc(VFSTONFS(vnode_mount(dvp)), dvp,
2000 np->n_fhp->nfh_fh, np->n_fhp->nfh_len,
2001 nfhp->nfh_fh, nfhp->nfh_len,
2002 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), op,
2003 name, namelen, &dp, 0, 0x0, cred, p, 0, 1);
2004 if (ret == NFSERR_DELAY)
2005 (void) nfs_catnap(PZERO, ret, "nfs_crt2");
2006 } while (ret == NFSERR_DELAY);
2007 if (ret) {
2008 if (dp != NULL)
2009 FREE((caddr_t)dp, M_NFSCLDELEG);
2010 if (ret == NFSERR_STALECLIENTID ||
2011 ret == NFSERR_STALEDONTRECOVER)
2012 error = ret;
2013 }
2014 }
2015 nfscl_openrelease(op, error, newone);
2016 *unlockedp = 1;
2017 }
2018 if (nd->nd_repstat != 0 && error == 0)
2019 error = nd->nd_repstat;
2020 if (error == NFSERR_STALECLIENTID)
2021 nfscl_initiate_recovery(owp->nfsow_clp);
2022nfsmout:
2023 if (!error)
2024 *dpp = dp;
2025 else if (dp != NULL)
2026 FREE((caddr_t)dp, M_NFSCLDELEG);
2027 mbuf_freem(nd->nd_mrep);
2028 return (error);
2029}
2030
2031/*
2032 * Nfs remove rpc
2033 */
2034APPLESTATIC int
2035nfsrpc_remove(vnode_t dvp, char *name, int namelen, vnode_t vp,
2036 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp,
2037 void *dstuff)
2038{
2039 u_int32_t *tl;
2040 struct nfsrv_descript nfsd, *nd = &nfsd;
2041 struct nfsnode *np;
2042 struct nfsmount *nmp;
2043 nfsv4stateid_t dstateid;
2044 int error, ret = 0, i;
2045
2046 *dattrflagp = 0;
2047 if (namelen > NFS_MAXNAMLEN)
2048 return (ENAMETOOLONG);
2049 nmp = VFSTONFS(vnode_mount(dvp));
2050tryagain:
2051 if (NFSHASNFSV4(nmp) && ret == 0) {
2052 ret = nfscl_removedeleg(vp, p, &dstateid);
2053 if (ret == 1) {
2054 NFSCL_REQSTART(nd, NFSPROC_RETDELEGREMOVE, vp);
2055 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID +
2056 NFSX_UNSIGNED);
2057 *tl++ = dstateid.seqid;
2058 *tl++ = dstateid.other[0];
2059 *tl++ = dstateid.other[1];
2060 *tl++ = dstateid.other[2];
2061 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2062 np = VTONFS(dvp);
2063 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
2064 np->n_fhp->nfh_len, 0);
2065 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2066 *tl = txdr_unsigned(NFSV4OP_REMOVE);
2067 }
2068 } else {
2069 ret = 0;
2070 }
2071 if (ret == 0)
2072 NFSCL_REQSTART(nd, NFSPROC_REMOVE, dvp);
2073 (void) nfsm_strtom(nd, name, namelen);
2074 error = nfscl_request(nd, dvp, p, cred, dstuff);
2075 if (error)
2076 return (error);
2077 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
2078 /* For NFSv4, parse out any Delereturn replies. */
2079 if (ret > 0 && nd->nd_repstat != 0 &&
2080 (nd->nd_flag & ND_NOMOREDATA)) {
2081 /*
2082 * If the Delegreturn failed, try again without
2083 * it. The server will Recall, as required.
2084 */
2085 mbuf_freem(nd->nd_mrep);
2086 goto tryagain;
2087 }
2088 for (i = 0; i < (ret * 2); i++) {
2089 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
2090 ND_NFSV4) {
2091 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2092 if (*(tl + 1))
2093 nd->nd_flag |= ND_NOMOREDATA;
2094 }
2095 }
2096 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2097 }
2098 if (nd->nd_repstat && !error)
2099 error = nd->nd_repstat;
2100nfsmout:
2101 mbuf_freem(nd->nd_mrep);
2102 return (error);
2103}
2104
2105/*
2106 * Do an nfs rename rpc.
2107 */
2108APPLESTATIC int
2109nfsrpc_rename(vnode_t fdvp, vnode_t fvp, char *fnameptr, int fnamelen,
2110 vnode_t tdvp, vnode_t tvp, char *tnameptr, int tnamelen, struct ucred *cred,
2111 NFSPROC_T *p, struct nfsvattr *fnap, struct nfsvattr *tnap,
2112 int *fattrflagp, int *tattrflagp, void *fstuff, void *tstuff)
2113{
2114 u_int32_t *tl;
2115 struct nfsrv_descript nfsd, *nd = &nfsd;
2116 struct nfsmount *nmp;
2117 struct nfsnode *np;
2118 nfsattrbit_t attrbits;
2119 nfsv4stateid_t fdstateid, tdstateid;
2120 int error = 0, ret = 0, gottd = 0, gotfd = 0, i;
2121
2122 *fattrflagp = 0;
2123 *tattrflagp = 0;
2124 nmp = VFSTONFS(vnode_mount(fdvp));
2125 if (fnamelen > NFS_MAXNAMLEN || tnamelen > NFS_MAXNAMLEN)
2126 return (ENAMETOOLONG);
2127tryagain:
2128 if (NFSHASNFSV4(nmp) && ret == 0) {
2129 ret = nfscl_renamedeleg(fvp, &fdstateid, &gotfd, tvp,
2130 &tdstateid, &gottd, p);
2131 if (gotfd && gottd) {
2132 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME2, fvp);
2133 } else if (gotfd) {
2134 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, fvp);
2135 } else if (gottd) {
2136 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, tvp);
2137 }
2138 if (gotfd) {
2139 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2140 *tl++ = fdstateid.seqid;
2141 *tl++ = fdstateid.other[0];
2142 *tl++ = fdstateid.other[1];
2143 *tl = fdstateid.other[2];
2144 if (gottd) {
2145 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2146 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2147 np = VTONFS(tvp);
2148 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
2149 np->n_fhp->nfh_len, 0);
2150 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2151 *tl = txdr_unsigned(NFSV4OP_DELEGRETURN);
2152 }
2153 }
2154 if (gottd) {
2155 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2156 *tl++ = tdstateid.seqid;
2157 *tl++ = tdstateid.other[0];
2158 *tl++ = tdstateid.other[1];
2159 *tl = tdstateid.other[2];
2160 }
2161 if (ret > 0) {
2162 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2163 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2164 np = VTONFS(fdvp);
2165 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
2166 np->n_fhp->nfh_len, 0);
2167 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2168 *tl = txdr_unsigned(NFSV4OP_SAVEFH);
2169 }
2170 } else {
2171 ret = 0;
2172 }
2173 if (ret == 0)
2174 NFSCL_REQSTART(nd, NFSPROC_RENAME, fdvp);
2175 if (nd->nd_flag & ND_NFSV4) {
2176 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2177 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2178 NFSWCCATTR_ATTRBIT(&attrbits);
2179 (void) nfsrv_putattrbit(nd, &attrbits);
2180 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2181 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2182 (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh,
2183 VTONFS(tdvp)->n_fhp->nfh_len, 0);
2184 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2185 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2186 (void) nfsrv_putattrbit(nd, &attrbits);
2187 nd->nd_flag |= ND_V4WCCATTR;
2188 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2189 *tl = txdr_unsigned(NFSV4OP_RENAME);
2190 }
2191 (void) nfsm_strtom(nd, fnameptr, fnamelen);
2192 if (!(nd->nd_flag & ND_NFSV4))
2193 (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh,
2194 VTONFS(tdvp)->n_fhp->nfh_len, 0);
2195 (void) nfsm_strtom(nd, tnameptr, tnamelen);
2196 error = nfscl_request(nd, fdvp, p, cred, fstuff);
2197 if (error)
2198 return (error);
2199 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
2200 /* For NFSv4, parse out any Delereturn replies. */
2201 if (ret > 0 && nd->nd_repstat != 0 &&
2202 (nd->nd_flag & ND_NOMOREDATA)) {
2203 /*
2204 * If the Delegreturn failed, try again without
2205 * it. The server will Recall, as required.
2206 */
2207 mbuf_freem(nd->nd_mrep);
2208 goto tryagain;
2209 }
2210 for (i = 0; i < (ret * 2); i++) {
2211 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
2212 ND_NFSV4) {
2213 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2214 if (*(tl + 1)) {
2215 if (i == 0 && ret > 1) {
2216 /*
2217 * If the Delegreturn failed, try again
2218 * without it. The server will Recall, as
2219 * required.
2220 * If ret > 1, the first iteration of this
2221 * loop is the second DelegReturn result.
2222 */
2223 mbuf_freem(nd->nd_mrep);
2224 goto tryagain;
2225 } else {
2226 nd->nd_flag |= ND_NOMOREDATA;
2227 }
2228 }
2229 }
2230 }
2231 /* Now, the first wcc attribute reply. */
2232 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
2233 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2234 if (*(tl + 1))
2235 nd->nd_flag |= ND_NOMOREDATA;
2236 }
2237 error = nfscl_wcc_data(nd, fdvp, fnap, fattrflagp, NULL,
2238 fstuff);
2239 /* and the second wcc attribute reply. */
2240 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 &&
2241 !error) {
2242 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2243 if (*(tl + 1))
2244 nd->nd_flag |= ND_NOMOREDATA;
2245 }
2246 if (!error)
2247 error = nfscl_wcc_data(nd, tdvp, tnap, tattrflagp,
2248 NULL, tstuff);
2249 }
2250 if (nd->nd_repstat && !error)
2251 error = nd->nd_repstat;
2252nfsmout:
2253 mbuf_freem(nd->nd_mrep);
2254 return (error);
2255}
2256
2257/*
2258 * nfs hard link create rpc
2259 */
2260APPLESTATIC int
2261nfsrpc_link(vnode_t dvp, vnode_t vp, char *name, int namelen,
2262 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
2263 struct nfsvattr *nap, int *attrflagp, int *dattrflagp, void *dstuff)
2264{
2265 u_int32_t *tl;
2266 struct nfsrv_descript nfsd, *nd = &nfsd;
2267 nfsattrbit_t attrbits;
2268 int error = 0;
2269
2270 *attrflagp = 0;
2271 *dattrflagp = 0;
2272 if (namelen > NFS_MAXNAMLEN)
2273 return (ENAMETOOLONG);
2274 NFSCL_REQSTART(nd, NFSPROC_LINK, vp);
2275 if (nd->nd_flag & ND_NFSV4) {
2276 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2277 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2278 }
2279 (void) nfsm_fhtom(nd, VTONFS(dvp)->n_fhp->nfh_fh,
2280 VTONFS(dvp)->n_fhp->nfh_len, 0);
2281 if (nd->nd_flag & ND_NFSV4) {
2282 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2283 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2284 NFSWCCATTR_ATTRBIT(&attrbits);
2285 (void) nfsrv_putattrbit(nd, &attrbits);
2286 nd->nd_flag |= ND_V4WCCATTR;
2287 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2288 *tl = txdr_unsigned(NFSV4OP_LINK);
2289 }
2290 (void) nfsm_strtom(nd, name, namelen);
2291 error = nfscl_request(nd, vp, p, cred, dstuff);
2292 if (error)
2293 return (error);
2294 if (nd->nd_flag & ND_NFSV3) {
2295 error = nfscl_postop_attr(nd, nap, attrflagp, dstuff);
2296 if (!error)
2297 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp,
2298 NULL, dstuff);
2299 } else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
2300 /*
2301 * First, parse out the PutFH and Getattr result.
2302 */
2303 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2304 if (!(*(tl + 1)))
2305 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2306 if (*(tl + 1))
2307 nd->nd_flag |= ND_NOMOREDATA;
2308 /*
2309 * Get the pre-op attributes.
2310 */
2311 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2312 }
2313 if (nd->nd_repstat && !error)
2314 error = nd->nd_repstat;
2315nfsmout:
2316 mbuf_freem(nd->nd_mrep);
2317 return (error);
2318}
2319
2320/*
2321 * nfs symbolic link create rpc
2322 */
2323APPLESTATIC int
2324nfsrpc_symlink(vnode_t dvp, char *name, int namelen, char *target,
2325 struct vattr *vap, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
2326 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
2327 int *dattrflagp, void *dstuff)
2328{
2329 u_int32_t *tl;
2330 struct nfsrv_descript nfsd, *nd = &nfsd;
2331 struct nfsmount *nmp;
2332 int slen, error = 0;
2333
2334 *nfhpp = NULL;
2335 *attrflagp = 0;
2336 *dattrflagp = 0;
2337 nmp = VFSTONFS(vnode_mount(dvp));
2338 slen = strlen(target);
2339 if (slen > NFS_MAXPATHLEN || namelen > NFS_MAXNAMLEN)
2340 return (ENAMETOOLONG);
2341 NFSCL_REQSTART(nd, NFSPROC_SYMLINK, dvp);
2342 if (nd->nd_flag & ND_NFSV4) {
2343 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2344 *tl = txdr_unsigned(NFLNK);
2345 (void) nfsm_strtom(nd, target, slen);
2346 }
2347 (void) nfsm_strtom(nd, name, namelen);
2348 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
2349 nfscl_fillsattr(nd, vap, dvp, 0, 0);
2350 if (!(nd->nd_flag & ND_NFSV4))
2351 (void) nfsm_strtom(nd, target, slen);
2352 if (nd->nd_flag & ND_NFSV2)
2353 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0);
2354 error = nfscl_request(nd, dvp, p, cred, dstuff);
2355 if (error)
2356 return (error);
2357 if (nd->nd_flag & ND_NFSV4)
2358 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2359 if ((nd->nd_flag & ND_NFSV3) && !error) {
2360 if (!nd->nd_repstat)
2361 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
2362 if (!error)
2363 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp,
2364 NULL, dstuff);
2365 }
2366 if (nd->nd_repstat && !error)
2367 error = nd->nd_repstat;
2368 mbuf_freem(nd->nd_mrep);
2369 /*
2370 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
2371 */
2372 if (error == EEXIST)
2373 error = 0;
2374 return (error);
2375}
2376
2377/*
2378 * nfs make dir rpc
2379 */
2380APPLESTATIC int
2381nfsrpc_mkdir(vnode_t dvp, char *name, int namelen, struct vattr *vap,
2382 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
2383 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
2384 int *dattrflagp, void *dstuff)
2385{
2386 u_int32_t *tl;
2387 struct nfsrv_descript nfsd, *nd = &nfsd;
2388 nfsattrbit_t attrbits;
2389 int error = 0;
2390
2391 *nfhpp = NULL;
2392 *attrflagp = 0;
2393 *dattrflagp = 0;
2394 if (namelen > NFS_MAXNAMLEN)
2395 return (ENAMETOOLONG);
2396 NFSCL_REQSTART(nd, NFSPROC_MKDIR, dvp);
2397 if (nd->nd_flag & ND_NFSV4) {
2398 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2399 *tl = txdr_unsigned(NFDIR);
2400 }
2401 (void) nfsm_strtom(nd, name, namelen);
2402 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0);
2403 if (nd->nd_flag & ND_NFSV4) {
2404 NFSGETATTR_ATTRBIT(&attrbits);
2405 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2406 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
2407 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2408 (void) nfsrv_putattrbit(nd, &attrbits);
2409 }
2410 error = nfscl_request(nd, dvp, p, cred, dstuff);
2411 if (error)
2412 return (error);
2413 if (nd->nd_flag & ND_NFSV4)
2414 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2415 if (!nd->nd_repstat && !error) {
2416 if (nd->nd_flag & ND_NFSV4) {
2417 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2418 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
2419 }
2420 if (!error)
2421 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
2422 }
2423 if ((nd->nd_flag & ND_NFSV3) && !error)
2424 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2425 if (nd->nd_repstat && !error)
2426 error = nd->nd_repstat;
2427nfsmout:
2428 mbuf_freem(nd->nd_mrep);
2429 /*
2430 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry.
2431 */
2432 if (error == EEXIST)
2433 error = 0;
2434 return (error);
2435}
2436
2437/*
2438 * nfs remove directory call
2439 */
2440APPLESTATIC int
2441nfsrpc_rmdir(vnode_t dvp, char *name, int namelen, struct ucred *cred,
2442 NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp, void *dstuff)
2443{
2444 struct nfsrv_descript nfsd, *nd = &nfsd;
2445 int error = 0;
2446
2447 *dattrflagp = 0;
2448 if (namelen > NFS_MAXNAMLEN)
2449 return (ENAMETOOLONG);
2450 NFSCL_REQSTART(nd, NFSPROC_RMDIR, dvp);
2451 (void) nfsm_strtom(nd, name, namelen);
2452 error = nfscl_request(nd, dvp, p, cred, dstuff);
2453 if (error)
2454 return (error);
2455 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
2456 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2457 if (nd->nd_repstat && !error)
2458 error = nd->nd_repstat;
2459 mbuf_freem(nd->nd_mrep);
2460 /*
2461 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
2462 */
2463 if (error == ENOENT)
2464 error = 0;
2465 return (error);
2466}
2467
2468/*
2469 * Readdir rpc.
2470 * Always returns with either uio_resid unchanged, if you are at the
2471 * end of the directory, or uio_resid == 0, with all DIRBLKSIZ chunks
2472 * filled in.
2473 * I felt this would allow caching of directory blocks more easily
2474 * than returning a pertially filled block.
2475 * Directory offset cookies:
2476 * Oh my, what to do with them...
2477 * I can think of three ways to deal with them:
2478 * 1 - have the layer above these RPCs maintain a map between logical
2479 * directory byte offsets and the NFS directory offset cookies
2480 * 2 - pass the opaque directory offset cookies up into userland
2481 * and let the libc functions deal with them, via the system call
2482 * 3 - return them to userland in the "struct dirent", so future versions
2483 * of libc can use them and do whatever is necessary to amke things work
2484 * above these rpc calls, in the meantime
2485 * For now, I do #3 by "hiding" the directory offset cookies after the
2486 * d_name field in struct dirent. This is space inside d_reclen that
2487 * will be ignored by anything that doesn't know about them.
2488 * The directory offset cookies are filled in as the last 8 bytes of
2489 * each directory entry, after d_name. Someday, the userland libc
2490 * functions may be able to use these. In the meantime, it satisfies
2491 * OpenBSD's requirements for cookies being returned.
2492 * If expects the directory offset cookie for the read to be in uio_offset
2493 * and returns the one for the next entry after this directory block in
2494 * there, as well.
2495 */
2496APPLESTATIC int
2497nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
2498 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
2499 int *eofp, void *stuff)
2500{
2501 int len, left;
2502 struct dirent *dp = NULL;
2503 u_int32_t *tl;
2504 nfsquad_t cookie, ncookie;
2505 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
2506 struct nfsnode *dnp = VTONFS(vp);
2507 struct nfsvattr nfsva;
2508 struct nfsrv_descript nfsd, *nd = &nfsd;
2509 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
2510 int reqsize, tryformoredirs = 1, readsize, eof = 0, gotmnton = 0;
2511 long dotfileid, dotdotfileid = 0;
2512 u_int32_t fakefileno = 0xffffffff, rderr;
2513 char *cp;
2514 nfsattrbit_t attrbits, dattrbits;
2515 u_int32_t *tl2 = NULL;
2516 size_t tresid;
2517
2518 KASSERT(uiop->uio_iovcnt == 1 &&
2519 (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0,
2520 ("nfs readdirrpc bad uio"));
2521
2522 /*
2523 * There is no point in reading a lot more than uio_resid, however
2524 * adding one additional DIRBLKSIZ makes sense. Since uio_resid
2525 * and nm_readdirsize are both exact multiples of DIRBLKSIZ, this
2526 * will never make readsize > nm_readdirsize.
2527 */
2528 readsize = nmp->nm_readdirsize;
2529 if (readsize > uio_uio_resid(uiop))
2530 readsize = uio_uio_resid(uiop) + DIRBLKSIZ;
2531
2532 *attrflagp = 0;
2533 if (eofp)
2534 *eofp = 0;
2535 tresid = uio_uio_resid(uiop);
2536 cookie.lval[0] = cookiep->nfsuquad[0];
2537 cookie.lval[1] = cookiep->nfsuquad[1];
2538 nd->nd_mrep = NULL;
2539
2540 /*
2541 * For NFSv4, first create the "." and ".." entries.
2542 */
2543 if (NFSHASNFSV4(nmp)) {
2544 reqsize = 6 * NFSX_UNSIGNED;
2545 NFSGETATTR_ATTRBIT(&dattrbits);
2546 NFSZERO_ATTRBIT(&attrbits);
2547 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID);
2548 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TYPE);
2549 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
2550 NFSATTRBIT_MOUNTEDONFILEID)) {
2551 NFSSETBIT_ATTRBIT(&attrbits,
2552 NFSATTRBIT_MOUNTEDONFILEID);
2553 gotmnton = 1;
2554 } else {
2555 /*
2556 * Must fake it. Use the fileno, except when the
2557 * fsid is != to that of the directory. For that
2558 * case, generate a fake fileno that is not the same.
2559 */
2560 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID);
2561 gotmnton = 0;
2562 }
2563
2564 /*
2565 * Joy, oh joy. For V4 we get to hand craft '.' and '..'.
2566 */
2567 if (uiop->uio_offset == 0) {
2568#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000
2569 error = VOP_GETATTR(vp, &nfsva.na_vattr, cred);
2570#else
2571 error = VOP_GETATTR(vp, &nfsva.na_vattr, cred, p);
2572#endif
2573 if (error)
2574 return (error);
2575 dotfileid = nfsva.na_fileid;
2576 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp);
2577 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2578 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
2579 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2580 (void) nfsrv_putattrbit(nd, &attrbits);
2581 error = nfscl_request(nd, vp, p, cred, stuff);
2582 if (error)
2583 return (error);
2584 if (nd->nd_repstat == 0) {
2585 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
2586 len = fxdr_unsigned(int, *(tl + 2));
2587 if (len > 0 && len <= NFSX_V4FHMAX)
2588 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
2589 else
2590 error = EPERM;
2591 if (!error) {
2592 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
2593 nfsva.na_mntonfileno = 0xffffffff;
2594 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
2595 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
2596 NULL, NULL, NULL, p, cred);
2597 if (error) {
2598 dotdotfileid = dotfileid;
2599 } else if (gotmnton) {
2600 if (nfsva.na_mntonfileno != 0xffffffff)
2601 dotdotfileid = nfsva.na_mntonfileno;
2602 else
2603 dotdotfileid = nfsva.na_fileid;
2604 } else if (nfsva.na_filesid[0] ==
2605 dnp->n_vattr.na_filesid[0] &&
2606 nfsva.na_filesid[1] ==
2607 dnp->n_vattr.na_filesid[1]) {
2608 dotdotfileid = nfsva.na_fileid;
2609 } else {
2610 do {
2611 fakefileno--;
2612 } while (fakefileno ==
2613 nfsva.na_fileid);
2614 dotdotfileid = fakefileno;
2615 }
2616 }
2617 } else if (nd->nd_repstat == NFSERR_NOENT) {
2618 /*
2619 * Lookupp returns NFSERR_NOENT when we are
2620 * at the root, so just use the current dir.
2621 */
2622 nd->nd_repstat = 0;
2623 dotdotfileid = dotfileid;
2624 } else {
2625 error = nd->nd_repstat;
2626 }
2627 mbuf_freem(nd->nd_mrep);
2628 if (error)
2629 return (error);
2630 nd->nd_mrep = NULL;
2631 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
2632 dp->d_type = DT_DIR;
2633 dp->d_fileno = dotfileid;
2634 dp->d_namlen = 1;
2635 dp->d_name[0] = '.';
2636 dp->d_name[1] = '\0';
2637 dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
2638 /*
2639 * Just make these offset cookie 0.
2640 */
2641 tl = (u_int32_t *)&dp->d_name[4];
2642 *tl++ = 0;
2643 *tl = 0;
2644 blksiz += dp->d_reclen;
2645 uio_uio_resid_add(uiop, -(dp->d_reclen));
2646 uiop->uio_offset += dp->d_reclen;
2647 uio_iov_base_add(uiop, dp->d_reclen);
2648 uio_iov_len_add(uiop, -(dp->d_reclen));
2649 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
2650 dp->d_type = DT_DIR;
2651 dp->d_fileno = dotdotfileid;
2652 dp->d_namlen = 2;
2653 dp->d_name[0] = '.';
2654 dp->d_name[1] = '.';
2655 dp->d_name[2] = '\0';
2656 dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
2657 /*
2658 * Just make these offset cookie 0.
2659 */
2660 tl = (u_int32_t *)&dp->d_name[4];
2661 *tl++ = 0;
2662 *tl = 0;
2663 blksiz += dp->d_reclen;
2664 uio_uio_resid_add(uiop, -(dp->d_reclen));
2665 uiop->uio_offset += dp->d_reclen;
2666 uio_iov_base_add(uiop, dp->d_reclen);
2667 uio_iov_len_add(uiop, -(dp->d_reclen));
2668 }
2669 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_RDATTRERROR);
2670 } else {
2671 reqsize = 5 * NFSX_UNSIGNED;
2672 }
2673
2674
2675 /*
2676 * Loop around doing readdir rpc's of size readsize.
2677 * The stopping criteria is EOF or buffer full.
2678 */
2679 while (more_dirs && bigenough) {
2680 *attrflagp = 0;
2681 NFSCL_REQSTART(nd, NFSPROC_READDIR, vp);
2682 if (nd->nd_flag & ND_NFSV2) {
2683 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2684 *tl++ = cookie.lval[1];
2685 *tl = txdr_unsigned(readsize);
2686 } else {
2687 NFSM_BUILD(tl, u_int32_t *, reqsize);
2688 *tl++ = cookie.lval[0];
2689 *tl++ = cookie.lval[1];
2690 if (cookie.qval == 0) {
2691 *tl++ = 0;
2692 *tl++ = 0;
2693 } else {
2694 NFSLOCKNODE(dnp);
2695 *tl++ = dnp->n_cookieverf.nfsuquad[0];
2696 *tl++ = dnp->n_cookieverf.nfsuquad[1];
2697 NFSUNLOCKNODE(dnp);
2698 }
2699 if (nd->nd_flag & ND_NFSV4) {
2700 *tl++ = txdr_unsigned(readsize);
2701 *tl = txdr_unsigned(readsize);
2702 (void) nfsrv_putattrbit(nd, &attrbits);
2703 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2704 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2705 (void) nfsrv_putattrbit(nd, &dattrbits);
2706 } else {
2707 *tl = txdr_unsigned(readsize);
2708 }
2709 }
2710 error = nfscl_request(nd, vp, p, cred, stuff);
2711 if (error)
2712 return (error);
2713 if (!(nd->nd_flag & ND_NFSV2)) {
2714 if (nd->nd_flag & ND_NFSV3)
2715 error = nfscl_postop_attr(nd, nap, attrflagp,
2716 stuff);
2717 if (!nd->nd_repstat && !error) {
2718 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2719 NFSLOCKNODE(dnp);
2720 dnp->n_cookieverf.nfsuquad[0] = *tl++;
2721 dnp->n_cookieverf.nfsuquad[1] = *tl;
2722 NFSUNLOCKNODE(dnp);
2723 }
2724 }
2725 if (nd->nd_repstat || error) {
2726 if (!error)
2727 error = nd->nd_repstat;
2728 goto nfsmout;
2729 }
2730 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2731 more_dirs = fxdr_unsigned(int, *tl);
2732 if (!more_dirs)
2733 tryformoredirs = 0;
2734
2735 /* loop thru the dir entries, doctoring them to 4bsd form */
2736 while (more_dirs && bigenough) {
2737 if (nd->nd_flag & ND_NFSV4) {
2738 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
2739 ncookie.lval[0] = *tl++;
2740 ncookie.lval[1] = *tl++;
2741 len = fxdr_unsigned(int, *tl);
2742 } else if (nd->nd_flag & ND_NFSV3) {
2743 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
2744 nfsva.na_fileid = fxdr_hyper(tl);
2745 tl += 2;
2746 len = fxdr_unsigned(int, *tl);
2747 } else {
2748 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
2749 nfsva.na_fileid =
2750 fxdr_unsigned(long, *tl++);
2751 len = fxdr_unsigned(int, *tl);
2752 }
2753 if (len <= 0 || len > NFS_MAXNAMLEN) {
2754 error = EBADRPC;
2755 goto nfsmout;
2756 }
2757 tlen = NFSM_RNDUP(len);
2758 if (tlen == len)
2759 tlen += 4; /* To ensure null termination */
2760 left = DIRBLKSIZ - blksiz;
2761 if ((int)(tlen + DIRHDSIZ + NFSX_HYPER) > left) {
2762 dp->d_reclen += left;
2763 uio_iov_base_add(uiop, left);
2764 uio_iov_len_add(uiop, -(left));
2765 uio_uio_resid_add(uiop, -(left));
2766 uiop->uio_offset += left;
2767 blksiz = 0;
2768 }
2769 if ((int)(tlen + DIRHDSIZ + NFSX_HYPER) > uio_uio_resid(uiop))
2770 bigenough = 0;
2771 if (bigenough) {
2772 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
2773 dp->d_namlen = len;
2774 dp->d_reclen = tlen + DIRHDSIZ + NFSX_HYPER;
2775 dp->d_type = DT_UNKNOWN;
2776 blksiz += dp->d_reclen;
2777 if (blksiz == DIRBLKSIZ)
2778 blksiz = 0;
2779 uio_uio_resid_add(uiop, -(DIRHDSIZ));
2780 uiop->uio_offset += DIRHDSIZ;
2781 uio_iov_base_add(uiop, DIRHDSIZ);
2782 uio_iov_len_add(uiop, -(DIRHDSIZ));
2783 error = nfsm_mbufuio(nd, uiop, len);
2784 if (error)
2785 goto nfsmout;
2786 cp = CAST_DOWN(caddr_t, uio_iov_base(uiop));
2787 tlen -= len;
2788 *cp = '\0'; /* null terminate */
2789 cp += tlen; /* points to cookie storage */
2790 tl2 = (u_int32_t *)cp;
2791 uio_iov_base_add(uiop, (tlen + NFSX_HYPER));
2792 uio_iov_len_add(uiop, -(tlen + NFSX_HYPER));
2793 uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER));
2794 uiop->uio_offset += (tlen + NFSX_HYPER);
2795 } else {
2796 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
2797 if (error)
2798 goto nfsmout;
2799 }
2800 if (nd->nd_flag & ND_NFSV4) {
2801 rderr = 0;
2802 nfsva.na_mntonfileno = 0xffffffff;
2803 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
2804 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
2805 NULL, NULL, &rderr, p, cred);
2806 if (error)
2807 goto nfsmout;
2808 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2809 } else if (nd->nd_flag & ND_NFSV3) {
2810 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
2811 ncookie.lval[0] = *tl++;
2812 ncookie.lval[1] = *tl++;
2813 } else {
2814 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
2815 ncookie.lval[0] = 0;
2816 ncookie.lval[1] = *tl++;
2817 }
2818 if (bigenough) {
2819 if (nd->nd_flag & ND_NFSV4) {
2820 if (rderr) {
2821 dp->d_fileno = 0;
2822 } else {
2823 if (gotmnton) {
2824 if (nfsva.na_mntonfileno != 0xffffffff)
2825 dp->d_fileno = nfsva.na_mntonfileno;
2826 else
2827 dp->d_fileno = nfsva.na_fileid;
2828 } else if (nfsva.na_filesid[0] ==
2829 dnp->n_vattr.na_filesid[0] &&
2830 nfsva.na_filesid[1] ==
2831 dnp->n_vattr.na_filesid[1]) {
2832 dp->d_fileno = nfsva.na_fileid;
2833 } else {
2834 do {
2835 fakefileno--;
2836 } while (fakefileno ==
2837 nfsva.na_fileid);
2838 dp->d_fileno = fakefileno;
2839 }
2840 dp->d_type = vtonfs_dtype(nfsva.na_type);
2841 }
2842 } else {
2843 dp->d_fileno = nfsva.na_fileid;
2844 }
2845 *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] =
2846 ncookie.lval[0];
2847 *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] =
2848 ncookie.lval[1];
2849 }
2850 more_dirs = fxdr_unsigned(int, *tl);
2851 }
2852 /*
2853 * If at end of rpc data, get the eof boolean
2854 */
2855 if (!more_dirs) {
2856 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2857 eof = fxdr_unsigned(int, *tl);
2858 if (tryformoredirs)
2859 more_dirs = !eof;
2860 if (nd->nd_flag & ND_NFSV4) {
2861 error = nfscl_postop_attr(nd, nap, attrflagp,
2862 stuff);
2863 if (error)
2864 goto nfsmout;
2865 }
2866 }
2867 mbuf_freem(nd->nd_mrep);
2868 nd->nd_mrep = NULL;
2869 }
2870 /*
2871 * Fill last record, iff any, out to a multiple of DIRBLKSIZ
2872 * by increasing d_reclen for the last record.
2873 */
2874 if (blksiz > 0) {
2875 left = DIRBLKSIZ - blksiz;
2876 dp->d_reclen += left;
2877 uio_iov_base_add(uiop, left);
2878 uio_iov_len_add(uiop, -(left));
2879 uio_uio_resid_add(uiop, -(left));
2880 uiop->uio_offset += left;
2881 }
2882
2883 /*
2884 * If returning no data, assume end of file.
2885 * If not bigenough, return not end of file, since you aren't
2886 * returning all the data
2887 * Otherwise, return the eof flag from the server.
2888 */
2889 if (eofp) {
2890 if (tresid == ((size_t)(uio_uio_resid(uiop))))
2891 *eofp = 1;
2892 else if (!bigenough)
2893 *eofp = 0;
2894 else
2895 *eofp = eof;
2896 }
2897
2898 /*
2899 * Add extra empty records to any remaining DIRBLKSIZ chunks.
2900 */
2901 while (uio_uio_resid(uiop) > 0 && ((size_t)(uio_uio_resid(uiop))) != tresid) {
2902 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
2903 dp->d_type = DT_UNKNOWN;
2904 dp->d_fileno = 0;
2905 dp->d_namlen = 0;
2906 dp->d_name[0] = '\0';
2907 tl = (u_int32_t *)&dp->d_name[4];
2908 *tl++ = cookie.lval[0];
2909 *tl = cookie.lval[1];
2910 dp->d_reclen = DIRBLKSIZ;
2911 uio_iov_base_add(uiop, DIRBLKSIZ);
2912 uio_iov_len_add(uiop, -(DIRBLKSIZ));
2913 uio_uio_resid_add(uiop, -(DIRBLKSIZ));
2914 uiop->uio_offset += DIRBLKSIZ;
2915 }
2916
2917nfsmout:
2918 if (nd->nd_mrep != NULL)
2919 mbuf_freem(nd->nd_mrep);
2920 return (error);
2921}
2922
2923#ifndef APPLE
2924/*
2925 * NFS V3 readdir plus RPC. Used in place of nfsrpc_readdir().
2926 * (Also used for NFS V4 when mount flag set.)
2927 * (ditto above w.r.t. multiple of DIRBLKSIZ, etc.)
2928 */
2929APPLESTATIC int
2930nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
2931 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
2932 int *eofp, void *stuff)
2933{
2934 int len, left;
2935 struct dirent *dp = NULL;
2936 u_int32_t *tl;
2937 vnode_t newvp = NULLVP;
2938 struct nfsrv_descript nfsd, *nd = &nfsd;
2939 struct nameidata nami, *ndp = &nami;
2940 struct componentname *cnp = &ndp->ni_cnd;
2941 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
2942 struct nfsnode *dnp = VTONFS(vp), *np;
2943 struct nfsvattr nfsva;
2944 struct nfsfh *nfhp;
2945 nfsquad_t cookie, ncookie;
2946 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
2947 int attrflag, tryformoredirs = 1, eof = 0, gotmnton = 0;
2948 int isdotdot = 0, unlocknewvp = 0;
2949 long dotfileid, dotdotfileid = 0, fileno = 0;
2950 char *cp;
2951 nfsattrbit_t attrbits, dattrbits;
2952 size_t tresid;
2953 u_int32_t *tl2 = NULL, fakefileno = 0xffffffff, rderr;
2954
2955 KASSERT(uiop->uio_iovcnt == 1 &&
2956 (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0,
2957 ("nfs readdirplusrpc bad uio"));
2958 *attrflagp = 0;
2959 if (eofp != NULL)
2960 *eofp = 0;
2961 ndp->ni_dvp = vp;
2962 nd->nd_mrep = NULL;
2963 cookie.lval[0] = cookiep->nfsuquad[0];
2964 cookie.lval[1] = cookiep->nfsuquad[1];
2965 tresid = uio_uio_resid(uiop);
2966
2967 /*
2968 * For NFSv4, first create the "." and ".." entries.
2969 */
2970 if (NFSHASNFSV4(nmp)) {
2971 NFSGETATTR_ATTRBIT(&dattrbits);
2972 NFSZERO_ATTRBIT(&attrbits);
2973 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID);
2974 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
2975 NFSATTRBIT_MOUNTEDONFILEID)) {
2976 NFSSETBIT_ATTRBIT(&attrbits,
2977 NFSATTRBIT_MOUNTEDONFILEID);
2978 gotmnton = 1;
2979 } else {
2980 /*
2981 * Must fake it. Use the fileno, except when the
2982 * fsid is != to that of the directory. For that
2983 * case, generate a fake fileno that is not the same.
2984 */
2985 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID);
2986 gotmnton = 0;
2987 }
2988
2989 /*
2990 * Joy, oh joy. For V4 we get to hand craft '.' and '..'.
2991 */
2992 if (uiop->uio_offset == 0) {
2993#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000
2994 error = VOP_GETATTR(vp, &nfsva.na_vattr, cred);
2995#else
2996 error = VOP_GETATTR(vp, &nfsva.na_vattr, cred, p);
2997#endif
2998 if (error)
2999 return (error);
3000 dotfileid = nfsva.na_fileid;
3001 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp);
3002 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3003 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
3004 *tl = txdr_unsigned(NFSV4OP_GETATTR);
3005 (void) nfsrv_putattrbit(nd, &attrbits);
3006 error = nfscl_request(nd, vp, p, cred, stuff);
3007 if (error)
3008 return (error);
3009 if (nd->nd_repstat == 0) {
3010 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3011 len = fxdr_unsigned(int, *(tl + 2));
3012 if (len > 0 && len <= NFSX_V4FHMAX)
3013 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
3014 else
3015 error = EPERM;
3016 if (!error) {
3017 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
3018 nfsva.na_mntonfileno = 0xffffffff;
3019 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
3020 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
3021 NULL, NULL, NULL, p, cred);
3022 if (error) {
3023 dotdotfileid = dotfileid;
3024 } else if (gotmnton) {
3025 if (nfsva.na_mntonfileno != 0xffffffff)
3026 dotdotfileid = nfsva.na_mntonfileno;
3027 else
3028 dotdotfileid = nfsva.na_fileid;
3029 } else if (nfsva.na_filesid[0] ==
3030 dnp->n_vattr.na_filesid[0] &&
3031 nfsva.na_filesid[1] ==
3032 dnp->n_vattr.na_filesid[1]) {
3033 dotdotfileid = nfsva.na_fileid;
3034 } else {
3035 do {
3036 fakefileno--;
3037 } while (fakefileno ==
3038 nfsva.na_fileid);
3039 dotdotfileid = fakefileno;
3040 }
3041 }
3042 } else if (nd->nd_repstat == NFSERR_NOENT) {
3043 /*
3044 * Lookupp returns NFSERR_NOENT when we are
3045 * at the root, so just use the current dir.
3046 */
3047 nd->nd_repstat = 0;
3048 dotdotfileid = dotfileid;
3049 } else {
3050 error = nd->nd_repstat;
3051 }
3052 mbuf_freem(nd->nd_mrep);
3053 if (error)
3054 return (error);
3055 nd->nd_mrep = NULL;
3056 dp = (struct dirent *)uio_iov_base(uiop);
3057 dp->d_type = DT_DIR;
3058 dp->d_fileno = dotfileid;
3059 dp->d_namlen = 1;
3060 dp->d_name[0] = '.';
3061 dp->d_name[1] = '\0';
3062 dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
3063 /*
3064 * Just make these offset cookie 0.
3065 */
3066 tl = (u_int32_t *)&dp->d_name[4];
3067 *tl++ = 0;
3068 *tl = 0;
3069 blksiz += dp->d_reclen;
3070 uio_uio_resid_add(uiop, -(dp->d_reclen));
3071 uiop->uio_offset += dp->d_reclen;
3072 uio_iov_base_add(uiop, dp->d_reclen);
3073 uio_iov_len_add(uiop, -(dp->d_reclen));
3074 dp = (struct dirent *)uio_iov_base(uiop);
3075 dp->d_type = DT_DIR;
3076 dp->d_fileno = dotdotfileid;
3077 dp->d_namlen = 2;
3078 dp->d_name[0] = '.';
3079 dp->d_name[1] = '.';
3080 dp->d_name[2] = '\0';
3081 dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
3082 /*
3083 * Just make these offset cookie 0.
3084 */
3085 tl = (u_int32_t *)&dp->d_name[4];
3086 *tl++ = 0;
3087 *tl = 0;
3088 blksiz += dp->d_reclen;
3089 uio_uio_resid_add(uiop, -(dp->d_reclen));
3090 uiop->uio_offset += dp->d_reclen;
3091 uio_iov_base_add(uiop, dp->d_reclen);
3092 uio_iov_len_add(uiop, -(dp->d_reclen));
3093 }
3094 NFSREADDIRPLUS_ATTRBIT(&attrbits);
3095 if (gotmnton)
3096 NFSSETBIT_ATTRBIT(&attrbits,
3097 NFSATTRBIT_MOUNTEDONFILEID);
3098 }
3099
3100 /*
3101 * Loop around doing readdir rpc's of size nm_readdirsize.
3102 * The stopping criteria is EOF or buffer full.
3103 */
3104 while (more_dirs && bigenough) {
3105 *attrflagp = 0;
3106 NFSCL_REQSTART(nd, NFSPROC_READDIRPLUS, vp);
3107 NFSM_BUILD(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
3108 *tl++ = cookie.lval[0];
3109 *tl++ = cookie.lval[1];
3110 if (cookie.qval == 0) {
3111 *tl++ = 0;
3112 *tl++ = 0;
3113 } else {
3114 NFSLOCKNODE(dnp);
3115 *tl++ = dnp->n_cookieverf.nfsuquad[0];
3116 *tl++ = dnp->n_cookieverf.nfsuquad[1];
3117 NFSUNLOCKNODE(dnp);
3118 }
3119 *tl++ = txdr_unsigned(nmp->nm_readdirsize);
3120 *tl = txdr_unsigned(nmp->nm_readdirsize);
3121 if (nd->nd_flag & ND_NFSV4) {
3122 (void) nfsrv_putattrbit(nd, &attrbits);
3123 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3124 *tl = txdr_unsigned(NFSV4OP_GETATTR);
3125 (void) nfsrv_putattrbit(nd, &dattrbits);
3126 }
3127 error = nfscl_request(nd, vp, p, cred, stuff);
3128 if (error)
3129 return (error);
3130 if (nd->nd_flag & ND_NFSV3)
3131 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3132 if (nd->nd_repstat || error) {
3133 if (!error)
3134 error = nd->nd_repstat;
3135 goto nfsmout;
3136 }
3137 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3138 NFSLOCKNODE(dnp);
3139 dnp->n_cookieverf.nfsuquad[0] = *tl++;
3140 dnp->n_cookieverf.nfsuquad[1] = *tl++;
3141 NFSUNLOCKNODE(dnp);
3142 more_dirs = fxdr_unsigned(int, *tl);
3143 if (!more_dirs)
3144 tryformoredirs = 0;
3145
3146 /* loop thru the dir entries, doctoring them to 4bsd form */
3147 while (more_dirs && bigenough) {
3148 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3149 if (nd->nd_flag & ND_NFSV4) {
3150 ncookie.lval[0] = *tl++;
3151 ncookie.lval[1] = *tl++;
3152 } else {
3153 fileno = fxdr_unsigned(long, *++tl);
3154 tl++;
3155 }
3156 len = fxdr_unsigned(int, *tl);
3157 if (len <= 0 || len > NFS_MAXNAMLEN) {
3158 error = EBADRPC;
3159 goto nfsmout;
3160 }
3161 tlen = NFSM_RNDUP(len);
3162 if (tlen == len)
3163 tlen += 4; /* To ensure null termination */
3164 left = DIRBLKSIZ - blksiz;
3165 if ((tlen + DIRHDSIZ + NFSX_HYPER) > left) {
3166 dp->d_reclen += left;
3167 uio_iov_base_add(uiop, left);
3168 uio_iov_len_add(uiop, -(left));
3169 uio_uio_resid_add(uiop, -(left));
3170 uiop->uio_offset += left;
3171 blksiz = 0;
3172 }
3173 if ((tlen + DIRHDSIZ + NFSX_HYPER) > uio_uio_resid(uiop))
3174 bigenough = 0;
3175 if (bigenough) {
3176 dp = (struct dirent *)uio_iov_base(uiop);
3177 dp->d_namlen = len;
3178 dp->d_reclen = tlen + DIRHDSIZ + NFSX_HYPER;
3179 dp->d_type = DT_UNKNOWN;
3180 blksiz += dp->d_reclen;
3181 if (blksiz == DIRBLKSIZ)
3182 blksiz = 0;
3183 uio_uio_resid_add(uiop, -(DIRHDSIZ));
3184 uiop->uio_offset += DIRHDSIZ;
3185 uio_iov_base_add(uiop, DIRHDSIZ);
3186 uio_iov_len_add(uiop, -(DIRHDSIZ));
3187 cnp->cn_nameptr = uio_iov_base(uiop);
3188 cnp->cn_namelen = len;
3189 NFSCNHASHZERO(cnp);
3190 error = nfsm_mbufuio(nd, uiop, len);
3191 if (error)
3192 goto nfsmout;
3193 cp = uio_iov_base(uiop);
3194 tlen -= len;
3195 *cp = '\0';
3196 cp += tlen; /* points to cookie storage */
3197 tl2 = (u_int32_t *)cp;
3198 if (len == 2 && cnp->cn_nameptr[0] == '.' &&
3199 cnp->cn_nameptr[1] == '.')
3200 isdotdot = 1;
3201 else
3202 isdotdot = 0;
3203 uio_iov_base_add(uiop, (tlen + NFSX_HYPER));
3204 uio_iov_len_add(uiop, -(tlen + NFSX_HYPER));
3205 uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER));
3206 uiop->uio_offset += (tlen + NFSX_HYPER);
3207 } else {
3208 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
3209 if (error)
3210 goto nfsmout;
3211 }
3212 nfhp = NULL;
3213 if (nd->nd_flag & ND_NFSV3) {
3214 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3215 ncookie.lval[0] = *tl++;
3216 ncookie.lval[1] = *tl++;
3217 attrflag = fxdr_unsigned(int, *tl);
3218 if (attrflag) {
3219 error = nfsm_loadattr(nd, &nfsva);
3220 if (error)
3221 goto nfsmout;
3222 }
3223 NFSM_DISSECT(tl,u_int32_t *,NFSX_UNSIGNED);
3224 if (*tl) {
3225 error = nfsm_getfh(nd, &nfhp);
3226 if (error)
3227 goto nfsmout;
3228 }
3229 if (!attrflag && nfhp != NULL) {
3230 FREE((caddr_t)nfhp, M_NFSFH);
3231 nfhp = NULL;
3232 }
3233 } else {
3234 rderr = 0;
3235 nfsva.na_mntonfileno = 0xffffffff;
3236 error = nfsv4_loadattr(nd, NULL, &nfsva, &nfhp,
3237 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
3238 NULL, NULL, &rderr, p, cred);
3239 if (error)
3240 goto nfsmout;
3241 }
3242
3243 if (bigenough) {
3244 if (nd->nd_flag & ND_NFSV4) {
3245 if (rderr) {
3246 dp->d_fileno = 0;
3247 } else if (gotmnton) {
3248 if (nfsva.na_mntonfileno != 0xffffffff)
3249 dp->d_fileno = nfsva.na_mntonfileno;
3250 else
3251 dp->d_fileno = nfsva.na_fileid;
3252 } else if (nfsva.na_filesid[0] ==
3253 dnp->n_vattr.na_filesid[0] &&
3254 nfsva.na_filesid[1] ==
3255 dnp->n_vattr.na_filesid[1]) {
3256 dp->d_fileno = nfsva.na_fileid;
3257 } else {
3258 do {
3259 fakefileno--;
3260 } while (fakefileno ==
3261 nfsva.na_fileid);
3262 dp->d_fileno = fakefileno;
3263 }
3264 } else {
3265 dp->d_fileno = fileno;
3266 }
3267 *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] =
3268 ncookie.lval[0];
3269 *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] =
3270 ncookie.lval[1];
3271
3272 if (nfhp != NULL) {
3273 if (NFSRV_CMPFH(nfhp->nfh_fh, nfhp->nfh_len,
3274 dnp->n_fhp->nfh_fh, dnp->n_fhp->nfh_len)) {
3275 VREF(vp);
3276 newvp = vp;
3277 unlocknewvp = 0;
3278 FREE((caddr_t)nfhp, M_NFSFH);
3279 np = dnp;
3280 } else if (isdotdot != 0) {
3281 /*
3282 * Skip doing a nfscl_nget() call for "..".
3283 * There's a race between acquiring the nfs
3284 * node here and lookups that look for the
3285 * directory being read (in the parent).
3286 * It would try to get a lock on ".." here,
3287 * owning the lock on the directory being
3288 * read. Lookup will hold the lock on ".."
3289 * and try to acquire the lock on the
3290 * directory being read.
3291 * If the directory is unlocked/relocked,
3292 * then there is a LOR with the buflock
3293 * vp is relocked.
3294 */
3295 free(nfhp, M_NFSFH);
3296 } else {
3297 error = nfscl_nget(vnode_mount(vp), vp,
3298 nfhp, cnp, p, &np, NULL, LK_EXCLUSIVE);
3299 if (!error) {
3300 newvp = NFSTOV(np);
3301 unlocknewvp = 1;
3302 }
3303 }
3304 nfhp = NULL;
3305 if (newvp != NULLVP) {
3306 error = nfscl_loadattrcache(&newvp,
3307 &nfsva, NULL, NULL, 0, 0);
3308 if (error) {
3309 if (unlocknewvp)
3310 vput(newvp);
3311 else
3312 vrele(newvp);
3313 goto nfsmout;
3314 }
3315 dp->d_type =
3316 vtonfs_dtype(np->n_vattr.na_type);
3317 ndp->ni_vp = newvp;
3318 NFSCNHASH(cnp, HASHINIT);
3319 if (cnp->cn_namelen <= NCHNAMLEN) {
36
37/*
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.
43 */
44
45#ifndef APPLEKEXT
46#include "opt_inet6.h"
47
48#include <fs/nfs/nfsport.h>
49
50/*
51 * Global variables
52 */
53extern int nfs_numnfscbd;
54extern struct timeval nfsboottime;
55extern u_int32_t newnfs_false, newnfs_true;
56extern nfstype nfsv34_type[9];
57extern int nfsrv_useacl;
58extern char nfsv4_callbackaddr[INET6_ADDRSTRLEN];
59NFSCLSTATEMUTEX;
60int nfstest_outofseq = 0;
61int nfscl_assumeposixlocks = 1;
62int nfscl_enablecallb = 0;
63short nfsv4_cbport = NFSV4_CBPORT;
64int nfstest_openallsetattr = 0;
65#endif /* !APPLEKEXT */
66
67#define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1))
68
69static int nfsrpc_setattrrpc(vnode_t , struct vattr *, nfsv4stateid_t *,
70 struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, void *);
71static int nfsrpc_readrpc(vnode_t , struct uio *, struct ucred *,
72 nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *, void *);
73static int nfsrpc_writerpc(vnode_t , struct uio *, int *, int *,
74 struct ucred *, nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *,
75 void *);
76static int nfsrpc_createv23(vnode_t , char *, int, struct vattr *,
77 nfsquad_t, int, struct ucred *, NFSPROC_T *, struct nfsvattr *,
78 struct nfsvattr *, struct nfsfh **, int *, int *, void *);
79static int nfsrpc_createv4(vnode_t , char *, int, struct vattr *,
80 nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, struct ucred *,
81 NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, struct nfsfh **, int *,
82 int *, void *, int *);
83static int nfsrpc_locku(struct nfsrv_descript *, struct nfsmount *,
84 struct nfscllockowner *, u_int64_t, u_int64_t,
85 u_int32_t, struct ucred *, NFSPROC_T *, int);
86static int nfsrpc_setaclrpc(vnode_t, struct ucred *, NFSPROC_T *,
87 struct acl *, nfsv4stateid_t *, void *);
88
89/*
90 * nfs null call from vfs.
91 */
92APPLESTATIC int
93nfsrpc_null(vnode_t vp, struct ucred *cred, NFSPROC_T *p)
94{
95 int error;
96 struct nfsrv_descript nfsd, *nd = &nfsd;
97
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);
103 return (error);
104}
105
106/*
107 * nfs access rpc op.
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.
110 */
111APPLESTATIC int
112nfsrpc_access(vnode_t vp, int acmode, struct ucred *cred,
113 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp)
114{
115 int error;
116 u_int32_t mode, rmode;
117
118 if (acmode & VREAD)
119 mode = NFSACCESS_READ;
120 else
121 mode = 0;
122 if (vnode_vtype(vp) == VDIR) {
123 if (acmode & VWRITE)
124 mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND |
125 NFSACCESS_DELETE);
126 if (acmode & VEXEC)
127 mode |= NFSACCESS_LOOKUP;
128 } else {
129 if (acmode & VWRITE)
130 mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND);
131 if (acmode & VEXEC)
132 mode |= NFSACCESS_EXECUTE;
133 }
134
135 /*
136 * Now, just call nfsrpc_accessrpc() to do the actual RPC.
137 */
138 error = nfsrpc_accessrpc(vp, mode, cred, p, nap, attrflagp, &rmode,
139 NULL);
140
141 /*
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...
145 */
146 if (!error && (rmode & mode) != mode)
147 error = EACCES;
148 return (error);
149}
150
151/*
152 * The actual rpc, separated out for Darwin.
153 */
154APPLESTATIC int
155nfsrpc_accessrpc(vnode_t vp, u_int32_t mode, struct ucred *cred,
156 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, u_int32_t *rmodep,
157 void *stuff)
158{
159 u_int32_t *tl;
160 u_int32_t supported, rmode;
161 int error;
162 struct nfsrv_descript nfsd, *nd = &nfsd;
163 nfsattrbit_t attrbits;
164
165 *attrflagp = 0;
166 supported = mode;
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) {
171 /*
172 * And do a Getattr op.
173 */
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);
178 }
179 error = nfscl_request(nd, vp, p, cred, stuff);
180 if (error)
181 return (error);
182 if (nd->nd_flag & ND_NFSV3) {
183 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
184 if (error)
185 goto nfsmout;
186 }
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++);
191 } else {
192 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
193 }
194 rmode = fxdr_unsigned(u_int32_t, *tl);
195 if (nd->nd_flag & ND_NFSV4)
196 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
197
198 /*
199 * It's not obvious what should be done about
200 * unsupported access modes. For now, be paranoid
201 * and clear the unsupported ones.
202 */
203 rmode &= supported;
204 *rmodep = rmode;
205 } else
206 error = nd->nd_repstat;
207nfsmout:
208 mbuf_freem(nd->nd_mrep);
209 return (error);
210}
211
212/*
213 * nfs open rpc
214 */
215APPLESTATIC int
216nfsrpc_open(vnode_t vp, int amode, struct ucred *cred, NFSPROC_T *p)
217{
218 struct nfsclopen *op;
219 struct nfscldeleg *dp;
220 struct nfsfh *nfhp;
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;
225
226 /*
227 * For NFSv4, Open Ops are only done on Regular Files.
228 */
229 if (vnode_vtype(vp) != VREG)
230 return (0);
231 mode = 0;
232 if (amode & FREAD)
233 mode |= NFSV4OPEN_ACCESSREAD;
234 if (amode & FWRITE)
235 mode |= NFSV4OPEN_ACCESSWRITE;
236 nfhp = np->n_fhp;
237
238 retrycnt = 0;
239#ifdef notdef
240{ char name[100]; int namel;
241namel = (np->n_v4->n4_namelen < 100) ? np->n_v4->n4_namelen : 99;
242bcopy(NFS4NODENAME(np->n_v4), name, namel);
243name[namel] = '\0';
244printf("rpcopen p=0x%x name=%s",p->p_pid,name);
245if (nfhp->nfh_len > 0) printf(" fh=0x%x\n",nfhp->nfh_fh[12]);
246else printf(" fhl=0\n");
247}
248#endif
249 do {
250 dp = NULL;
251 error = nfscl_open(vp, nfhp->nfh_fh, nfhp->nfh_len, mode, 1,
252 cred, p, NULL, &op, &newone, &ret, 1);
253 if (error) {
254 return (error);
255 }
256 if (nmp->nm_clp != NULL)
257 clidrev = nmp->nm_clp->nfsc_clientidrev;
258 else
259 clidrev = 0;
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);
267 if (dp != NULL) {
268#ifdef APPLE
269 OSBitAndAtomic((int32_t)~NDELEGMOD, (UInt32 *)&np->n_flag);
270#else
271 NFSLOCKNODE(np);
272 np->n_flag &= ~NDELEGMOD;
273 /*
274 * Invalidate the attribute cache, so that
275 * attributes that pre-date the issue of a
276 * delegation are not cached, since the
277 * cached attributes will remain valid while
278 * the delegation is held.
279 */
280 NFSINVALATTRCACHE(np);
281 NFSUNLOCKNODE(np);
282#endif
283 (void) nfscl_deleg(nmp->nm_mountp,
284 op->nfso_own->nfsow_clp,
285 nfhp->nfh_fh, nfhp->nfh_len, cred, p, &dp);
286 }
287 } else {
288 error = EIO;
289 }
290 newnfs_copyincred(cred, &op->nfso_cred);
291 } else if (ret == NFSCLOPEN_SETCRED)
292 /*
293 * This is a new local open on a delegation. It needs
294 * to have credentials so that an open can be done
295 * against the server during recovery.
296 */
297 newnfs_copyincred(cred, &op->nfso_cred);
298
299 /*
300 * nfso_opencnt is the count of how many VOP_OPEN()s have
301 * been done on this Open successfully and a VOP_CLOSE()
302 * is expected for each of these.
303 * If error is non-zero, don't increment it, since the Open
304 * hasn't succeeded yet.
305 */
306 if (!error)
307 op->nfso_opencnt++;
308 nfscl_openrelease(op, error, newone);
309 if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
310 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY) {
311 (void) nfs_catnap(PZERO, error, "nfs_open");
312 } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID)
313 && clidrev != 0) {
314 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
315 retrycnt++;
316 }
317 } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
318 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
319 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
320 expireret == 0 && clidrev != 0 && retrycnt < 4));
321 if (error && retrycnt >= 4)
322 error = EIO;
323 return (error);
324}
325
326/*
327 * the actual open rpc
328 */
329APPLESTATIC int
330nfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen,
331 u_int8_t *newfhp, int newfhlen, u_int32_t mode, struct nfsclopen *op,
332 u_int8_t *name, int namelen, struct nfscldeleg **dpp,
333 int reclaim, u_int32_t delegtype, struct ucred *cred, NFSPROC_T *p,
334 int syscred, int recursed)
335{
336 u_int32_t *tl;
337 struct nfsrv_descript nfsd, *nd = &nfsd;
338 struct nfscldeleg *dp, *ndp = NULL;
339 struct nfsvattr nfsva;
340 u_int32_t rflags, deleg;
341 nfsattrbit_t attrbits;
342 int error, ret, acesize, limitby;
343
344 dp = *dpp;
345 *dpp = NULL;
346 nfscl_reqstart(nd, NFSPROC_OPEN, nmp, nfhp, fhlen, NULL);
347 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
348 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
349 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
350 *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
351 *tl++ = op->nfso_own->nfsow_clp->nfsc_clientid.lval[0];
352 *tl = op->nfso_own->nfsow_clp->nfsc_clientid.lval[1];
353 (void) nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN);
354 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
355 *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE);
356 if (reclaim) {
357 *tl = txdr_unsigned(NFSV4OPEN_CLAIMPREVIOUS);
358 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
359 *tl = txdr_unsigned(delegtype);
360 } else {
361 if (dp != NULL) {
362 *tl = txdr_unsigned(NFSV4OPEN_CLAIMDELEGATECUR);
363 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
364 *tl++ = dp->nfsdl_stateid.seqid;
365 *tl++ = dp->nfsdl_stateid.other[0];
366 *tl++ = dp->nfsdl_stateid.other[1];
367 *tl = dp->nfsdl_stateid.other[2];
368 } else {
369 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
370 }
371 (void) nfsm_strtom(nd, name, namelen);
372 }
373 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
374 *tl = txdr_unsigned(NFSV4OP_GETATTR);
375 NFSZERO_ATTRBIT(&attrbits);
376 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
377 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY);
378 (void) nfsrv_putattrbit(nd, &attrbits);
379 if (syscred)
380 nd->nd_flag |= ND_USEGSSNAME;
381 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
382 NFS_PROG, NFS_VER4, NULL, 1, NULL);
383 if (error)
384 return (error);
385 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
386 if (!nd->nd_repstat) {
387 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
388 6 * NFSX_UNSIGNED);
389 op->nfso_stateid.seqid = *tl++;
390 op->nfso_stateid.other[0] = *tl++;
391 op->nfso_stateid.other[1] = *tl++;
392 op->nfso_stateid.other[2] = *tl;
393 rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
394 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
395 if (error)
396 goto nfsmout;
397 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
398 deleg = fxdr_unsigned(u_int32_t, *tl);
399 if (deleg == NFSV4OPEN_DELEGATEREAD ||
400 deleg == NFSV4OPEN_DELEGATEWRITE) {
401 if (!(op->nfso_own->nfsow_clp->nfsc_flags &
402 NFSCLFLAGS_FIRSTDELEG))
403 op->nfso_own->nfsow_clp->nfsc_flags |=
404 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
405 MALLOC(ndp, struct nfscldeleg *,
406 sizeof (struct nfscldeleg) + newfhlen,
407 M_NFSCLDELEG, M_WAITOK);
408 LIST_INIT(&ndp->nfsdl_owner);
409 LIST_INIT(&ndp->nfsdl_lock);
410 ndp->nfsdl_clp = op->nfso_own->nfsow_clp;
411 ndp->nfsdl_fhlen = newfhlen;
412 NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen);
413 newnfs_copyincred(cred, &ndp->nfsdl_cred);
414 nfscl_lockinit(&ndp->nfsdl_rwlock);
415 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
416 NFSX_UNSIGNED);
417 ndp->nfsdl_stateid.seqid = *tl++;
418 ndp->nfsdl_stateid.other[0] = *tl++;
419 ndp->nfsdl_stateid.other[1] = *tl++;
420 ndp->nfsdl_stateid.other[2] = *tl++;
421 ret = fxdr_unsigned(int, *tl);
422 if (deleg == NFSV4OPEN_DELEGATEWRITE) {
423 ndp->nfsdl_flags = NFSCLDL_WRITE;
424 /*
425 * Indicates how much the file can grow.
426 */
427 NFSM_DISSECT(tl, u_int32_t *,
428 3 * NFSX_UNSIGNED);
429 limitby = fxdr_unsigned(int, *tl++);
430 switch (limitby) {
431 case NFSV4OPEN_LIMITSIZE:
432 ndp->nfsdl_sizelimit = fxdr_hyper(tl);
433 break;
434 case NFSV4OPEN_LIMITBLOCKS:
435 ndp->nfsdl_sizelimit =
436 fxdr_unsigned(u_int64_t, *tl++);
437 ndp->nfsdl_sizelimit *=
438 fxdr_unsigned(u_int64_t, *tl);
439 break;
440 default:
441 error = NFSERR_BADXDR;
442 goto nfsmout;
443 };
444 } else {
445 ndp->nfsdl_flags = NFSCLDL_READ;
446 }
447 if (ret)
448 ndp->nfsdl_flags |= NFSCLDL_RECALL;
449 error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, &ret,
450 &acesize, p);
451 if (error)
452 goto nfsmout;
453 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
454 error = NFSERR_BADXDR;
455 goto nfsmout;
456 }
457 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
458 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
459 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
460 NULL, NULL, NULL, p, cred);
461 if (error)
462 goto nfsmout;
463 if (ndp != NULL) {
464 ndp->nfsdl_change = nfsva.na_filerev;
465 ndp->nfsdl_modtime = nfsva.na_mtime;
466 ndp->nfsdl_flags |= NFSCLDL_MODTIMESET;
467 }
468 if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM)) {
469 do {
470 ret = nfsrpc_openconfirm(vp, newfhp, newfhlen, op,
471 cred, p);
472 if (ret == NFSERR_DELAY)
473 (void) nfs_catnap(PZERO, ret, "nfs_open");
474 } while (ret == NFSERR_DELAY);
475 error = ret;
476 }
477 if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) ||
478 nfscl_assumeposixlocks)
479 op->nfso_posixlock = 1;
480 else
481 op->nfso_posixlock = 0;
482
483 /*
484 * If the server is handing out delegations, but we didn't
485 * get one because an OpenConfirm was required, try the
486 * Open again, to get a delegation. This is a harmless no-op,
487 * from a server's point of view.
488 */
489 if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM) &&
490 (op->nfso_own->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG)
491 && !error && dp == NULL && ndp == NULL && !recursed) {
492 do {
493 ret = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp,
494 newfhlen, mode, op, name, namelen, &ndp, 0, 0x0,
495 cred, p, syscred, 1);
496 if (ret == NFSERR_DELAY)
497 (void) nfs_catnap(PZERO, ret, "nfs_open2");
498 } while (ret == NFSERR_DELAY);
499 if (ret) {
500 if (ndp != NULL)
501 FREE((caddr_t)ndp, M_NFSCLDELEG);
502 if (ret == NFSERR_STALECLIENTID ||
503 ret == NFSERR_STALEDONTRECOVER)
504 error = ret;
505 }
506 }
507 }
508 if (nd->nd_repstat != 0 && error == 0)
509 error = nd->nd_repstat;
510 if (error == NFSERR_STALECLIENTID)
511 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
512nfsmout:
513 if (!error)
514 *dpp = ndp;
515 else if (ndp != NULL)
516 FREE((caddr_t)ndp, M_NFSCLDELEG);
517 mbuf_freem(nd->nd_mrep);
518 return (error);
519}
520
521/*
522 * open downgrade rpc
523 */
524APPLESTATIC int
525nfsrpc_opendowngrade(vnode_t vp, u_int32_t mode, struct nfsclopen *op,
526 struct ucred *cred, NFSPROC_T *p)
527{
528 u_int32_t *tl;
529 struct nfsrv_descript nfsd, *nd = &nfsd;
530 int error;
531
532 NFSCL_REQSTART(nd, NFSPROC_OPENDOWNGRADE, vp);
533 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
534 *tl++ = op->nfso_stateid.seqid;
535 *tl++ = op->nfso_stateid.other[0];
536 *tl++ = op->nfso_stateid.other[1];
537 *tl++ = op->nfso_stateid.other[2];
538 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
539 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
540 *tl = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
541 error = nfscl_request(nd, vp, p, cred, NULL);
542 if (error)
543 return (error);
544 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
545 if (!nd->nd_repstat) {
546 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
547 op->nfso_stateid.seqid = *tl++;
548 op->nfso_stateid.other[0] = *tl++;
549 op->nfso_stateid.other[1] = *tl++;
550 op->nfso_stateid.other[2] = *tl;
551 }
552 if (nd->nd_repstat && error == 0)
553 error = nd->nd_repstat;
554 if (error == NFSERR_STALESTATEID)
555 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
556nfsmout:
557 mbuf_freem(nd->nd_mrep);
558 return (error);
559}
560
561/*
562 * V4 Close operation.
563 */
564APPLESTATIC int
565nfsrpc_close(vnode_t vp, int doclose, NFSPROC_T *p)
566{
567 struct nfsclclient *clp;
568 int error;
569
570 if (vnode_vtype(vp) != VREG)
571 return (0);
572 if (doclose)
573 error = nfscl_doclose(vp, &clp, p);
574 else
575 error = nfscl_getclose(vp, &clp);
576 if (error)
577 return (error);
578
579 nfscl_clientrelease(clp);
580 return (0);
581}
582
583/*
584 * Close the open.
585 */
586APPLESTATIC void
587nfsrpc_doclose(struct nfsmount *nmp, struct nfsclopen *op, NFSPROC_T *p)
588{
589 struct nfsrv_descript nfsd, *nd = &nfsd;
590 struct nfscllockowner *lp, *nlp;
591 struct nfscllock *lop, *nlop;
592 struct ucred *tcred;
593 u_int64_t off = 0, len = 0;
594 u_int32_t type = NFSV4LOCKT_READ;
595 int error, do_unlock, trycnt;
596
597 tcred = newnfs_getcred();
598 newnfs_copycred(&op->nfso_cred, tcred);
599 /*
600 * (Theoretically this could be done in the same
601 * compound as the close, but having multiple
602 * sequenced Ops in the same compound might be
603 * too scary for some servers.)
604 */
605 if (op->nfso_posixlock) {
606 off = 0;
607 len = NFS64BITSSET;
608 type = NFSV4LOCKT_READ;
609 }
610
611 /*
612 * Since this function is only called from VOP_INACTIVE(), no
613 * other thread will be manipulating this Open. As such, the
614 * lock lists are not being changed by other threads, so it should
615 * be safe to do this without locking.
616 */
617 LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) {
618 do_unlock = 1;
619 LIST_FOREACH_SAFE(lop, &lp->nfsl_lock, nfslo_list, nlop) {
620 if (op->nfso_posixlock == 0) {
621 off = lop->nfslo_first;
622 len = lop->nfslo_end - lop->nfslo_first;
623 if (lop->nfslo_type == F_WRLCK)
624 type = NFSV4LOCKT_WRITE;
625 else
626 type = NFSV4LOCKT_READ;
627 }
628 if (do_unlock) {
629 trycnt = 0;
630 do {
631 error = nfsrpc_locku(nd, nmp, lp, off,
632 len, type, tcred, p, 0);
633 if ((nd->nd_repstat == NFSERR_GRACE ||
634 nd->nd_repstat == NFSERR_DELAY) &&
635 error == 0)
636 (void) nfs_catnap(PZERO,
637 (int)nd->nd_repstat,
638 "nfs_close");
639 } while ((nd->nd_repstat == NFSERR_GRACE ||
640 nd->nd_repstat == NFSERR_DELAY) &&
641 error == 0 && trycnt++ < 5);
642 if (op->nfso_posixlock)
643 do_unlock = 0;
644 }
645 nfscl_freelock(lop, 0);
646 }
647 /*
648 * Do a ReleaseLockOwner.
649 * The lock owner name nfsl_owner may be used by other opens for
650 * other files but the lock_owner4 name that nfsrpc_rellockown()
651 * puts on the wire has the file handle for this file appended
652 * to it, so it can be done now.
653 */
654 (void)nfsrpc_rellockown(nmp, lp, lp->nfsl_open->nfso_fh,
655 lp->nfsl_open->nfso_fhlen, tcred, p);
656 }
657
658 /*
659 * There could be other Opens for different files on the same
660 * OpenOwner, so locking is required.
661 */
662 NFSLOCKCLSTATE();
663 nfscl_lockexcl(&op->nfso_own->nfsow_rwlock, NFSCLSTATEMUTEXPTR);
664 NFSUNLOCKCLSTATE();
665 do {
666 error = nfscl_tryclose(op, tcred, nmp, p);
667 if (error == NFSERR_GRACE)
668 (void) nfs_catnap(PZERO, error, "nfs_close");
669 } while (error == NFSERR_GRACE);
670 NFSLOCKCLSTATE();
671 nfscl_lockunlock(&op->nfso_own->nfsow_rwlock);
672
673 LIST_FOREACH_SAFE(lp, &op->nfso_lock, nfsl_list, nlp)
674 nfscl_freelockowner(lp, 0);
675 nfscl_freeopen(op, 0);
676 NFSUNLOCKCLSTATE();
677 NFSFREECRED(tcred);
678}
679
680/*
681 * The actual Close RPC.
682 */
683APPLESTATIC int
684nfsrpc_closerpc(struct nfsrv_descript *nd, struct nfsmount *nmp,
685 struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p,
686 int syscred)
687{
688 u_int32_t *tl;
689 int error;
690
691 nfscl_reqstart(nd, NFSPROC_CLOSE, nmp, op->nfso_fh,
692 op->nfso_fhlen, NULL);
693 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
694 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
695 *tl++ = op->nfso_stateid.seqid;
696 *tl++ = op->nfso_stateid.other[0];
697 *tl++ = op->nfso_stateid.other[1];
698 *tl = op->nfso_stateid.other[2];
699 if (syscred)
700 nd->nd_flag |= ND_USEGSSNAME;
701 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
702 NFS_PROG, NFS_VER4, NULL, 1, NULL);
703 if (error)
704 return (error);
705 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
706 if (nd->nd_repstat == 0)
707 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
708 error = nd->nd_repstat;
709 if (error == NFSERR_STALESTATEID)
710 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
711nfsmout:
712 mbuf_freem(nd->nd_mrep);
713 return (error);
714}
715
716/*
717 * V4 Open Confirm RPC.
718 */
719APPLESTATIC int
720nfsrpc_openconfirm(vnode_t vp, u_int8_t *nfhp, int fhlen,
721 struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p)
722{
723 u_int32_t *tl;
724 struct nfsrv_descript nfsd, *nd = &nfsd;
725 int error;
726
727 nfscl_reqstart(nd, NFSPROC_OPENCONFIRM, VFSTONFS(vnode_mount(vp)),
728 nfhp, fhlen, NULL);
729 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
730 *tl++ = op->nfso_stateid.seqid;
731 *tl++ = op->nfso_stateid.other[0];
732 *tl++ = op->nfso_stateid.other[1];
733 *tl++ = op->nfso_stateid.other[2];
734 *tl = txdr_unsigned(op->nfso_own->nfsow_seqid);
735 error = nfscl_request(nd, vp, p, cred, NULL);
736 if (error)
737 return (error);
738 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
739 if (!nd->nd_repstat) {
740 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
741 op->nfso_stateid.seqid = *tl++;
742 op->nfso_stateid.other[0] = *tl++;
743 op->nfso_stateid.other[1] = *tl++;
744 op->nfso_stateid.other[2] = *tl;
745 }
746 error = nd->nd_repstat;
747 if (error == NFSERR_STALESTATEID)
748 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
749nfsmout:
750 mbuf_freem(nd->nd_mrep);
751 return (error);
752}
753
754/*
755 * Do the setclientid and setclientid confirm RPCs. Called from nfs_statfs()
756 * when a mount has just occurred and when the server replies NFSERR_EXPIRED.
757 */
758APPLESTATIC int
759nfsrpc_setclient(struct nfsmount *nmp, struct nfsclclient *clp,
760 struct ucred *cred, NFSPROC_T *p)
761{
762 u_int32_t *tl;
763 struct nfsrv_descript nfsd;
764 struct nfsrv_descript *nd = &nfsd;
765 nfsattrbit_t attrbits;
766 u_int8_t *cp = NULL, *cp2, addr[INET6_ADDRSTRLEN + 9];
767 u_short port;
768 int error, isinet6 = 0, callblen;
769 nfsquad_t confirm;
770 u_int32_t lease;
771 static u_int32_t rev = 0;
772
773 if (nfsboottime.tv_sec == 0)
774 NFSSETBOOTTIME(nfsboottime);
775 nfscl_reqstart(nd, NFSPROC_SETCLIENTID, nmp, NULL, 0, NULL);
776 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
777 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
778 *tl = txdr_unsigned(rev++);
779 (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen);
780
781 /*
782 * set up the callback address
783 */
784 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
785 *tl = txdr_unsigned(NFS_CALLBCKPROG);
786 callblen = strlen(nfsv4_callbackaddr);
787 if (callblen == 0)
788 cp = nfscl_getmyip(nmp, &isinet6);
789 if (nfscl_enablecallb && nfs_numnfscbd > 0 &&
790 (callblen > 0 || cp != NULL)) {
791 port = htons(nfsv4_cbport);
792 cp2 = (u_int8_t *)&port;
793#ifdef INET6
794 if ((callblen > 0 &&
795 strchr(nfsv4_callbackaddr, ':')) || isinet6) {
796 char ip6buf[INET6_ADDRSTRLEN], *ip6add;
797
798 (void) nfsm_strtom(nd, "tcp6", 4);
799 if (callblen == 0) {
800 ip6_sprintf(ip6buf, (struct in6_addr *)cp);
801 ip6add = ip6buf;
802 } else {
803 ip6add = nfsv4_callbackaddr;
804 }
805 snprintf(addr, INET6_ADDRSTRLEN + 9, "%s.%d.%d",
806 ip6add, cp2[0], cp2[1]);
807 } else
808#endif
809 {
810 (void) nfsm_strtom(nd, "tcp", 3);
811 if (callblen == 0)
812 snprintf(addr, INET6_ADDRSTRLEN + 9,
813 "%d.%d.%d.%d.%d.%d", cp[0], cp[1],
814 cp[2], cp[3], cp2[0], cp2[1]);
815 else
816 snprintf(addr, INET6_ADDRSTRLEN + 9,
817 "%s.%d.%d", nfsv4_callbackaddr,
818 cp2[0], cp2[1]);
819 }
820 (void) nfsm_strtom(nd, addr, strlen(addr));
821 } else {
822 (void) nfsm_strtom(nd, "tcp", 3);
823 (void) nfsm_strtom(nd, "0.0.0.0.0.0", 11);
824 }
825 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
826 *tl = txdr_unsigned(clp->nfsc_cbident);
827 nd->nd_flag |= ND_USEGSSNAME;
828 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
829 NFS_PROG, NFS_VER4, NULL, 1, NULL);
830 if (error)
831 return (error);
832 if (nd->nd_repstat == 0) {
833 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
834 clp->nfsc_clientid.lval[0] = *tl++;
835 clp->nfsc_clientid.lval[1] = *tl++;
836 confirm.lval[0] = *tl++;
837 confirm.lval[1] = *tl;
838 mbuf_freem(nd->nd_mrep);
839 nd->nd_mrep = NULL;
840
841 /*
842 * and confirm it.
843 */
844 nfscl_reqstart(nd, NFSPROC_SETCLIENTIDCFRM, nmp, NULL, 0, NULL);
845 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
846 *tl++ = clp->nfsc_clientid.lval[0];
847 *tl++ = clp->nfsc_clientid.lval[1];
848 *tl++ = confirm.lval[0];
849 *tl = confirm.lval[1];
850 nd->nd_flag |= ND_USEGSSNAME;
851 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p,
852 cred, NFS_PROG, NFS_VER4, NULL, 1, NULL);
853 if (error)
854 return (error);
855 mbuf_freem(nd->nd_mrep);
856 nd->nd_mrep = NULL;
857 if (nd->nd_repstat == 0) {
858 nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, nmp->nm_fh,
859 nmp->nm_fhsize, NULL);
860 NFSZERO_ATTRBIT(&attrbits);
861 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME);
862 (void) nfsrv_putattrbit(nd, &attrbits);
863 nd->nd_flag |= ND_USEGSSNAME;
864 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p,
865 cred, NFS_PROG, NFS_VER4, NULL, 1, NULL);
866 if (error)
867 return (error);
868 if (nd->nd_repstat == 0) {
869 error = nfsv4_loadattr(nd, NULL, NULL, NULL, NULL, 0, NULL,
870 NULL, NULL, NULL, NULL, 0, NULL, &lease, NULL, p, cred);
871 if (error)
872 goto nfsmout;
873 clp->nfsc_renew = NFSCL_RENEW(lease);
874 clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew;
875 clp->nfsc_clientidrev++;
876 if (clp->nfsc_clientidrev == 0)
877 clp->nfsc_clientidrev++;
878 }
879 }
880 }
881 error = nd->nd_repstat;
882nfsmout:
883 mbuf_freem(nd->nd_mrep);
884 return (error);
885}
886
887/*
888 * nfs getattr call.
889 */
890APPLESTATIC int
891nfsrpc_getattr(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
892 struct nfsvattr *nap, void *stuff)
893{
894 struct nfsrv_descript nfsd, *nd = &nfsd;
895 int error;
896 nfsattrbit_t attrbits;
897
898 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
899 if (nd->nd_flag & ND_NFSV4) {
900 NFSGETATTR_ATTRBIT(&attrbits);
901 (void) nfsrv_putattrbit(nd, &attrbits);
902 }
903 error = nfscl_request(nd, vp, p, cred, stuff);
904 if (error)
905 return (error);
906 if (!nd->nd_repstat)
907 error = nfsm_loadattr(nd, nap);
908 else
909 error = nd->nd_repstat;
910 mbuf_freem(nd->nd_mrep);
911 return (error);
912}
913
914/*
915 * nfs getattr call with non-vnode arguemnts.
916 */
917APPLESTATIC int
918nfsrpc_getattrnovp(struct nfsmount *nmp, u_int8_t *fhp, int fhlen, int syscred,
919 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, u_int64_t *xidp)
920{
921 struct nfsrv_descript nfsd, *nd = &nfsd;
922 int error, vers = NFS_VER2;
923 nfsattrbit_t attrbits;
924
925 nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, fhp, fhlen, NULL);
926 if (nd->nd_flag & ND_NFSV4) {
927 vers = NFS_VER4;
928 NFSGETATTR_ATTRBIT(&attrbits);
929 (void) nfsrv_putattrbit(nd, &attrbits);
930 } else if (nd->nd_flag & ND_NFSV3) {
931 vers = NFS_VER3;
932 }
933 if (syscred)
934 nd->nd_flag |= ND_USEGSSNAME;
935 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
936 NFS_PROG, vers, NULL, 1, xidp);
937 if (error)
938 return (error);
939 if (!nd->nd_repstat)
940 error = nfsm_loadattr(nd, nap);
941 else
942 error = nd->nd_repstat;
943 mbuf_freem(nd->nd_mrep);
944 return (error);
945}
946
947/*
948 * Do an nfs setattr operation.
949 */
950APPLESTATIC int
951nfsrpc_setattr(vnode_t vp, struct vattr *vap, NFSACL_T *aclp,
952 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *rnap, int *attrflagp,
953 void *stuff)
954{
955 int error, expireret = 0, openerr, retrycnt;
956 u_int32_t clidrev = 0, mode;
957 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
958 struct nfsfh *nfhp;
959 nfsv4stateid_t stateid;
960 void *lckp;
961
962 if (nmp->nm_clp != NULL)
963 clidrev = nmp->nm_clp->nfsc_clientidrev;
964 if (vap != NULL && NFSATTRISSET(u_quad_t, vap, va_size))
965 mode = NFSV4OPEN_ACCESSWRITE;
966 else
967 mode = NFSV4OPEN_ACCESSREAD;
968 retrycnt = 0;
969 do {
970 lckp = NULL;
971 openerr = 1;
972 if (NFSHASNFSV4(nmp)) {
973 nfhp = VTONFS(vp)->n_fhp;
974 error = nfscl_getstateid(vp, nfhp->nfh_fh,
975 nfhp->nfh_len, mode, cred, p, &stateid, &lckp);
976 if (error && vnode_vtype(vp) == VREG &&
977 (mode == NFSV4OPEN_ACCESSWRITE ||
978 nfstest_openallsetattr)) {
979 /*
980 * No Open stateid, so try and open the file
981 * now.
982 */
983 if (mode == NFSV4OPEN_ACCESSWRITE)
984 openerr = nfsrpc_open(vp, FWRITE, cred,
985 p);
986 else
987 openerr = nfsrpc_open(vp, FREAD, cred,
988 p);
989 if (!openerr)
990 (void) nfscl_getstateid(vp,
991 nfhp->nfh_fh, nfhp->nfh_len,
992 mode, cred, p, &stateid, &lckp);
993 }
994 }
995 if (vap != NULL)
996 error = nfsrpc_setattrrpc(vp, vap, &stateid, cred, p,
997 rnap, attrflagp, stuff);
998 else
999 error = nfsrpc_setaclrpc(vp, cred, p, aclp, &stateid,
1000 stuff);
1001 if (error == NFSERR_STALESTATEID)
1002 nfscl_initiate_recovery(nmp->nm_clp);
1003 if (lckp != NULL)
1004 nfscl_lockderef(lckp);
1005 if (!openerr)
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);
1014 }
1015 retrycnt++;
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)
1022 error = EIO;
1023 return (error);
1024}
1025
1026static int
1027nfsrpc_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)
1030{
1031 u_int32_t *tl;
1032 struct nfsrv_descript nfsd, *nd = &nfsd;
1033 int error;
1034 nfsattrbit_t attrbits;
1035
1036 *attrflagp = 0;
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);
1044 *tl = newnfs_false;
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);
1050 }
1051 error = nfscl_request(nd, vp, p, cred, stuff);
1052 if (error)
1053 return (error);
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;
1063 return (error);
1064}
1065
1066/*
1067 * nfs lookup rpc
1068 */
1069APPLESTATIC int
1070nfsrpc_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)
1073{
1074 u_int32_t *tl;
1075 struct nfsrv_descript nfsd, *nd = &nfsd;
1076 struct nfsmount *nmp;
1077 struct nfsnode *np;
1078 struct nfsfh *nfhp;
1079 nfsattrbit_t attrbits;
1080 int error = 0, lookupp = 0;
1081
1082 *attrflagp = 0;
1083 *dattrflagp = 0;
1084 if (vnode_vtype(dvp) != VDIR)
1085 return (ENOTDIR);
1086 nmp = VFSTONFS(vnode_mount(dvp));
1087 if (len > NFS_MAXNAMLEN)
1088 return (ENAMETOOLONG);
1089 if (NFSHASNFSV4(nmp) && len == 1 &&
1090 name[0] == '.') {
1091 /*
1092 * Just return the current dir's fh.
1093 */
1094 np = VTONFS(dvp);
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);
1099 *nfhpp = nfhp;
1100 return (0);
1101 }
1102 if (NFSHASNFSV4(nmp) && len == 2 &&
1103 name[0] == '.' && name[1] == '.') {
1104 lookupp = 1;
1105 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, dvp);
1106 } else {
1107 NFSCL_REQSTART(nd, NFSPROC_LOOKUP, dvp);
1108 (void) nfsm_strtom(nd, name, len);
1109 }
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);
1116 }
1117 error = nfscl_request(nd, dvp, p, cred, stuff);
1118 if (error)
1119 return (error);
1120 if (nd->nd_repstat) {
1121 /*
1122 * When an NFSv4 Lookupp returns ENOENT, it means that
1123 * the lookup is at the root of an fs, so return this dir.
1124 */
1125 if (nd->nd_repstat == NFSERR_NOENT && lookupp) {
1126 np = VTONFS(dvp);
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);
1131 *nfhpp = nfhp;
1132 mbuf_freem(nd->nd_mrep);
1133 return (0);
1134 }
1135 if (nd->nd_flag & ND_NFSV3)
1136 error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff);
1137 goto nfsmout;
1138 }
1139 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
1140 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1141 if (*(tl + 1)) {
1142 nd->nd_flag |= ND_NOMOREDATA;
1143 goto nfsmout;
1144 }
1145 }
1146 error = nfsm_getfh(nd, nfhpp);
1147 if (error)
1148 goto nfsmout;
1149
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);
1153nfsmout:
1154 mbuf_freem(nd->nd_mrep);
1155 if (!error && nd->nd_repstat)
1156 error = nd->nd_repstat;
1157 return (error);
1158}
1159
1160/*
1161 * Do a readlink rpc.
1162 */
1163APPLESTATIC int
1164nfsrpc_readlink(vnode_t vp, struct uio *uiop, struct ucred *cred,
1165 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
1166{
1167 u_int32_t *tl;
1168 struct nfsrv_descript nfsd, *nd = &nfsd;
1169 struct nfsnode *np = VTONFS(vp);
1170 nfsattrbit_t attrbits;
1171 int error, len, cangetattr = 1;
1172
1173 *attrflagp = 0;
1174 NFSCL_REQSTART(nd, NFSPROC_READLINK, vp);
1175 if (nd->nd_flag & ND_NFSV4) {
1176 /*
1177 * And do a Getattr op.
1178 */
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);
1183 }
1184 error = nfscl_request(nd, vp, p, cred, stuff);
1185 if (error)
1186 return (error);
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);
1191 /*
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?
1196 */
1197 if (len == NFS_MAXPATHLEN) {
1198 NFSLOCKNODE(np);
1199 if (np->n_size > 0 && np->n_size < NFS_MAXPATHLEN) {
1200 len = np->n_size;
1201 cangetattr = 0;
1202 }
1203 NFSUNLOCKNODE(np);
1204 }
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);
1208 }
1209 if (nd->nd_repstat && !error)
1210 error = nd->nd_repstat;
1211nfsmout:
1212 mbuf_freem(nd->nd_mrep);
1213 return (error);
1214}
1215
1216/*
1217 * Read operation.
1218 */
1219APPLESTATIC int
1220nfsrpc_read(vnode_t vp, struct uio *uiop, struct ucred *cred,
1221 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
1222{
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;
1230 void *lckp;
1231
1232 if (nmp->nm_clp != NULL)
1233 clidrev = nmp->nm_clp->nfsc_clientidrev;
1234 newcred = cred;
1235 if (NFSHASNFSV4(nmp)) {
1236 nfhp = np->n_fhp;
1237 newcred = NFSNEWCRED(cred);
1238 }
1239 retrycnt = 0;
1240 do {
1241 lckp = NULL;
1242 if (NFSHASNFSV4(nmp))
1243 (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
1244 NFSV4OPEN_ACCESSREAD, newcred, p, &stateid, &lckp);
1245 error = nfsrpc_readrpc(vp, uiop, newcred, &stateid, p, nap,
1246 attrflagp, stuff);
1247 if (error == NFSERR_STALESTATEID)
1248 nfscl_initiate_recovery(nmp->nm_clp);
1249 if (lckp != NULL)
1250 nfscl_lockderef(lckp);
1251 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1252 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1253 error == NFSERR_OLDSTATEID) {
1254 (void) nfs_catnap(PZERO, error, "nfs_read");
1255 } else if ((error == NFSERR_EXPIRED ||
1256 error == NFSERR_BADSTATEID) && clidrev != 0) {
1257 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1258 }
1259 retrycnt++;
1260 } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1261 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1262 (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
1263 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1264 expireret == 0 && clidrev != 0 && retrycnt < 4));
1265 if (error && retrycnt >= 4)
1266 error = EIO;
1267 if (NFSHASNFSV4(nmp))
1268 NFSFREECRED(newcred);
1269 return (error);
1270}
1271
1272/*
1273 * The actual read RPC.
1274 */
1275static int
1276nfsrpc_readrpc(vnode_t vp, struct uio *uiop, struct ucred *cred,
1277 nfsv4stateid_t *stateidp, NFSPROC_T *p, struct nfsvattr *nap,
1278 int *attrflagp, void *stuff)
1279{
1280 u_int32_t *tl;
1281 int error = 0, len, retlen, tsiz, eof = 0;
1282 struct nfsrv_descript nfsd;
1283 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1284 struct nfsrv_descript *nd = &nfsd;
1285 int rsize;
1286 off_t tmp_off;
1287
1288 *attrflagp = 0;
1289 tsiz = uio_uio_resid(uiop);
1290 tmp_off = uiop->uio_offset + tsiz;
1291 NFSLOCKMNT(nmp);
1292 if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) {
1293 NFSUNLOCKMNT(nmp);
1294 return (EFBIG);
1295 }
1296 rsize = nmp->nm_rsize;
1297 NFSUNLOCKMNT(nmp);
1298 nd->nd_mrep = NULL;
1299 while (tsiz > 0) {
1300 *attrflagp = 0;
1301 len = (tsiz > rsize) ? rsize : tsiz;
1302 NFSCL_REQSTART(nd, NFSPROC_READ, vp);
1303 if (nd->nd_flag & ND_NFSV4)
1304 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
1305 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED * 3);
1306 if (nd->nd_flag & ND_NFSV2) {
1307 *tl++ = txdr_unsigned(uiop->uio_offset);
1308 *tl++ = txdr_unsigned(len);
1309 *tl = 0;
1310 } else {
1311 txdr_hyper(uiop->uio_offset, tl);
1312 *(tl + 2) = txdr_unsigned(len);
1313 }
1314 /*
1315 * Since I can't do a Getattr for NFSv4 for Write, there
1316 * doesn't seem any point in doing one here, either.
1317 * (See the comment in nfsrpc_writerpc() for more info.)
1318 */
1319 error = nfscl_request(nd, vp, p, cred, stuff);
1320 if (error)
1321 return (error);
1322 if (nd->nd_flag & ND_NFSV3) {
1323 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
1324 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
1325 error = nfsm_loadattr(nd, nap);
1326 if (!error)
1327 *attrflagp = 1;
1328 }
1329 if (nd->nd_repstat || error) {
1330 if (!error)
1331 error = nd->nd_repstat;
1332 goto nfsmout;
1333 }
1334 if (nd->nd_flag & ND_NFSV3) {
1335 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1336 eof = fxdr_unsigned(int, *(tl + 1));
1337 } else if (nd->nd_flag & ND_NFSV4) {
1338 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1339 eof = fxdr_unsigned(int, *tl);
1340 }
1341 NFSM_STRSIZ(retlen, rsize);
1342 error = nfsm_mbufuio(nd, uiop, retlen);
1343 if (error)
1344 goto nfsmout;
1345 mbuf_freem(nd->nd_mrep);
1346 nd->nd_mrep = NULL;
1347 tsiz -= retlen;
1348 if (!(nd->nd_flag & ND_NFSV2)) {
1349 if (eof || retlen == 0)
1350 tsiz = 0;
1351 } else if (retlen < len)
1352 tsiz = 0;
1353 }
1354 return (0);
1355nfsmout:
1356 if (nd->nd_mrep != NULL)
1357 mbuf_freem(nd->nd_mrep);
1358 return (error);
1359}
1360
1361/*
1362 * nfs write operation
1363 * When called_from_strategy != 0, it should return EIO for an error that
1364 * indicates recovery is in progress, so that the buffer will be left
1365 * dirty and be written back to the server later. If it loops around,
1366 * the recovery thread could get stuck waiting for the buffer and recovery
1367 * will then deadlock.
1368 */
1369APPLESTATIC int
1370nfsrpc_write(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
1371 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
1372 void *stuff, int called_from_strategy)
1373{
1374 int error, expireret = 0, retrycnt, nostateid;
1375 u_int32_t clidrev = 0;
1376 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1377 struct nfsnode *np = VTONFS(vp);
1378 struct ucred *newcred;
1379 struct nfsfh *nfhp = NULL;
1380 nfsv4stateid_t stateid;
1381 void *lckp;
1382
1383 *must_commit = 0;
1384 if (nmp->nm_clp != NULL)
1385 clidrev = nmp->nm_clp->nfsc_clientidrev;
1386 newcred = cred;
1387 if (NFSHASNFSV4(nmp)) {
1388 newcred = NFSNEWCRED(cred);
1389 nfhp = np->n_fhp;
1390 }
1391 retrycnt = 0;
1392 do {
1393 lckp = NULL;
1394 nostateid = 0;
1395 if (NFSHASNFSV4(nmp)) {
1396 (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
1397 NFSV4OPEN_ACCESSWRITE, newcred, p, &stateid, &lckp);
1398 if (stateid.other[0] == 0 && stateid.other[1] == 0 &&
1399 stateid.other[2] == 0) {
1400 nostateid = 1;
1401 printf("stateid0 in write\n");
1402 }
1403 }
1404
1405 /*
1406 * If there is no stateid for NFSv4, it means this is an
1407 * extraneous write after close. Basically a poorly
1408 * implemented buffer cache. Just don't do the write.
1409 */
1410 if (nostateid)
1411 error = 0;
1412 else
1413 error = nfsrpc_writerpc(vp, uiop, iomode, must_commit,
1414 newcred, &stateid, p, nap, attrflagp, stuff);
1415 if (error == NFSERR_STALESTATEID)
1416 nfscl_initiate_recovery(nmp->nm_clp);
1417 if (lckp != NULL)
1418 nfscl_lockderef(lckp);
1419 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1420 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1421 error == NFSERR_OLDSTATEID) {
1422 (void) nfs_catnap(PZERO, error, "nfs_write");
1423 } else if ((error == NFSERR_EXPIRED ||
1424 error == NFSERR_BADSTATEID) && clidrev != 0) {
1425 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1426 }
1427 retrycnt++;
1428 } while (error == NFSERR_GRACE || error == NFSERR_DELAY ||
1429 ((error == NFSERR_STALESTATEID ||
1430 error == NFSERR_STALEDONTRECOVER) && called_from_strategy == 0) ||
1431 (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
1432 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1433 expireret == 0 && clidrev != 0 && retrycnt < 4));
1434 if (error != 0 && (retrycnt >= 4 ||
1435 ((error == NFSERR_STALESTATEID ||
1436 error == NFSERR_STALEDONTRECOVER) && called_from_strategy != 0)))
1437 error = EIO;
1438 if (NFSHASNFSV4(nmp))
1439 NFSFREECRED(newcred);
1440 return (error);
1441}
1442
1443/*
1444 * The actual write RPC.
1445 */
1446static int
1447nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode,
1448 int *must_commit, struct ucred *cred, nfsv4stateid_t *stateidp,
1449 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
1450{
1451 u_int32_t *tl;
1452 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
1453 struct nfsnode *np = VTONFS(vp);
1454 int error = 0, len, tsiz, rlen, commit, committed = NFSWRITE_FILESYNC;
1455 int wccflag = 0, wsize;
1456 int32_t backup;
1457 struct nfsrv_descript nfsd;
1458 struct nfsrv_descript *nd = &nfsd;
1459 nfsattrbit_t attrbits;
1460 off_t tmp_off;
1461
1462 KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1"));
1463 *attrflagp = 0;
1464 tsiz = uio_uio_resid(uiop);
1465 tmp_off = uiop->uio_offset + tsiz;
1466 NFSLOCKMNT(nmp);
1467 if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) {
1468 NFSUNLOCKMNT(nmp);
1469 return (EFBIG);
1470 }
1471 wsize = nmp->nm_wsize;
1472 NFSUNLOCKMNT(nmp);
1473 nd->nd_mrep = NULL; /* NFSv2 sometimes does a write with */
1474 nd->nd_repstat = 0; /* uio_resid == 0, so the while is not done */
1475 while (tsiz > 0) {
1476 *attrflagp = 0;
1477 len = (tsiz > wsize) ? wsize : tsiz;
1478 NFSCL_REQSTART(nd, NFSPROC_WRITE, vp);
1479 if (nd->nd_flag & ND_NFSV4) {
1480 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
1481 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+2*NFSX_UNSIGNED);
1482 txdr_hyper(uiop->uio_offset, tl);
1483 tl += 2;
1484 *tl++ = txdr_unsigned(*iomode);
1485 *tl = txdr_unsigned(len);
1486 } else if (nd->nd_flag & ND_NFSV3) {
1487 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+3*NFSX_UNSIGNED);
1488 txdr_hyper(uiop->uio_offset, tl);
1489 tl += 2;
1490 *tl++ = txdr_unsigned(len);
1491 *tl++ = txdr_unsigned(*iomode);
1492 *tl = txdr_unsigned(len);
1493 } else {
1494 u_int32_t x;
1495
1496 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1497 /*
1498 * Not sure why someone changed this, since the
1499 * RFC clearly states that "beginoffset" and
1500 * "totalcount" are ignored, but it wouldn't
1501 * surprise me if there's a busted server out there.
1502 */
1503 /* Set both "begin" and "current" to non-garbage. */
1504 x = txdr_unsigned((u_int32_t)uiop->uio_offset);
1505 *tl++ = x; /* "begin offset" */
1506 *tl++ = x; /* "current offset" */
1507 x = txdr_unsigned(len);
1508 *tl++ = x; /* total to this offset */
1509 *tl = x; /* size of this write */
1510
1511 }
1512 nfsm_uiombuf(nd, uiop, len);
1513 /*
1514 * Although it is tempting to do a normal Getattr Op in the
1515 * NFSv4 compound, the result can be a nearly hung client
1516 * system if the Getattr asks for Owner and/or OwnerGroup.
1517 * It occurs when the client can't map either the Owner or
1518 * Owner_group name in the Getattr reply to a uid/gid. When
1519 * there is a cache miss, the kernel does an upcall to the
1520 * nfsuserd. Then, it can try and read the local /etc/passwd
1521 * or /etc/group file. It can then block in getnewbuf(),
1522 * waiting for dirty writes to be pushed to the NFS server.
1523 * The only reason this doesn't result in a complete
1524 * deadlock, is that the upcall times out and allows
1525 * the write to complete. However, progress is so slow
1526 * that it might just as well be deadlocked.
1527 * As such, we get the rest of the attributes, but not
1528 * Owner or Owner_group.
1529 * nb: nfscl_loadattrcache() needs to be told that these
1530 * partial attributes from a write rpc are being
1531 * passed in, via a argument flag.
1532 */
1533 if (nd->nd_flag & ND_NFSV4) {
1534 NFSWRITEGETATTR_ATTRBIT(&attrbits);
1535 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1536 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1537 (void) nfsrv_putattrbit(nd, &attrbits);
1538 }
1539 error = nfscl_request(nd, vp, p, cred, stuff);
1540 if (error)
1541 return (error);
1542 if (nd->nd_repstat) {
1543 /*
1544 * In case the rpc gets retried, roll
1545 * the uio fileds changed by nfsm_uiombuf()
1546 * back.
1547 */
1548 uiop->uio_offset -= len;
1549 uio_uio_resid_add(uiop, len);
1550 uio_iov_base_add(uiop, -len);
1551 uio_iov_len_add(uiop, len);
1552 }
1553 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1554 error = nfscl_wcc_data(nd, vp, nap, attrflagp,
1555 &wccflag, stuff);
1556 if (error)
1557 goto nfsmout;
1558 }
1559 if (!nd->nd_repstat) {
1560 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1561 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED
1562 + NFSX_VERF);
1563 rlen = fxdr_unsigned(int, *tl++);
1564 if (rlen == 0) {
1565 error = NFSERR_IO;
1566 goto nfsmout;
1567 } else if (rlen < len) {
1568 backup = len - rlen;
1569 uio_iov_base_add(uiop, -(backup));
1570 uio_iov_len_add(uiop, backup);
1571 uiop->uio_offset -= backup;
1572 uio_uio_resid_add(uiop, backup);
1573 len = rlen;
1574 }
1575 commit = fxdr_unsigned(int, *tl++);
1576
1577 /*
1578 * Return the lowest committment level
1579 * obtained by any of the RPCs.
1580 */
1581 if (committed == NFSWRITE_FILESYNC)
1582 committed = commit;
1583 else if (committed == NFSWRITE_DATASYNC &&
1584 commit == NFSWRITE_UNSTABLE)
1585 committed = commit;
1586 NFSLOCKMNT(nmp);
1587 if (!NFSHASWRITEVERF(nmp)) {
1588 NFSBCOPY((caddr_t)tl,
1589 (caddr_t)&nmp->nm_verf[0],
1590 NFSX_VERF);
1591 NFSSETWRITEVERF(nmp);
1592 } else if (NFSBCMP(tl, nmp->nm_verf,
1593 NFSX_VERF)) {
1594 *must_commit = 1;
1595 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
1596 }
1597 NFSUNLOCKMNT(nmp);
1598 }
1599 if (nd->nd_flag & ND_NFSV4)
1600 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1601 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV4)) {
1602 error = nfsm_loadattr(nd, nap);
1603 if (!error)
1604 *attrflagp = NFS_LATTR_NOSHRINK;
1605 }
1606 } else {
1607 error = nd->nd_repstat;
1608 }
1609 if (error)
1610 goto nfsmout;
1611 NFSWRITERPC_SETTIME(wccflag, np, (nd->nd_flag & ND_NFSV4));
1612 mbuf_freem(nd->nd_mrep);
1613 nd->nd_mrep = NULL;
1614 tsiz -= len;
1615 }
1616nfsmout:
1617 if (nd->nd_mrep != NULL)
1618 mbuf_freem(nd->nd_mrep);
1619 *iomode = committed;
1620 if (nd->nd_repstat && !error)
1621 error = nd->nd_repstat;
1622 return (error);
1623}
1624
1625/*
1626 * nfs mknod rpc
1627 * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the
1628 * mode set to specify the file type and the size field for rdev.
1629 */
1630APPLESTATIC int
1631nfsrpc_mknod(vnode_t dvp, char *name, int namelen, struct vattr *vap,
1632 u_int32_t rdev, enum vtype vtyp, struct ucred *cred, NFSPROC_T *p,
1633 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
1634 int *attrflagp, int *dattrflagp, void *dstuff)
1635{
1636 u_int32_t *tl;
1637 int error = 0;
1638 struct nfsrv_descript nfsd, *nd = &nfsd;
1639 nfsattrbit_t attrbits;
1640
1641 *nfhpp = NULL;
1642 *attrflagp = 0;
1643 *dattrflagp = 0;
1644 if (namelen > NFS_MAXNAMLEN)
1645 return (ENAMETOOLONG);
1646 NFSCL_REQSTART(nd, NFSPROC_MKNOD, dvp);
1647 if (nd->nd_flag & ND_NFSV4) {
1648 if (vtyp == VBLK || vtyp == VCHR) {
1649 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1650 *tl++ = vtonfsv34_type(vtyp);
1651 *tl++ = txdr_unsigned(NFSMAJOR(rdev));
1652 *tl = txdr_unsigned(NFSMINOR(rdev));
1653 } else {
1654 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1655 *tl = vtonfsv34_type(vtyp);
1656 }
1657 }
1658 (void) nfsm_strtom(nd, name, namelen);
1659 if (nd->nd_flag & ND_NFSV3) {
1660 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1661 *tl = vtonfsv34_type(vtyp);
1662 }
1663 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
1664 nfscl_fillsattr(nd, vap, dvp, 0, 0);
1665 if ((nd->nd_flag & ND_NFSV3) &&
1666 (vtyp == VCHR || vtyp == VBLK)) {
1667 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1668 *tl++ = txdr_unsigned(NFSMAJOR(rdev));
1669 *tl = txdr_unsigned(NFSMINOR(rdev));
1670 }
1671 if (nd->nd_flag & ND_NFSV4) {
1672 NFSGETATTR_ATTRBIT(&attrbits);
1673 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1674 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
1675 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1676 (void) nfsrv_putattrbit(nd, &attrbits);
1677 }
1678 if (nd->nd_flag & ND_NFSV2)
1679 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZERDEV, rdev);
1680 error = nfscl_request(nd, dvp, p, cred, dstuff);
1681 if (error)
1682 return (error);
1683 if (nd->nd_flag & ND_NFSV4)
1684 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
1685 if (!nd->nd_repstat) {
1686 if (nd->nd_flag & ND_NFSV4) {
1687 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1688 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1689 if (error)
1690 goto nfsmout;
1691 }
1692 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
1693 if (error)
1694 goto nfsmout;
1695 }
1696 if (nd->nd_flag & ND_NFSV3)
1697 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
1698 if (!error && nd->nd_repstat)
1699 error = nd->nd_repstat;
1700nfsmout:
1701 mbuf_freem(nd->nd_mrep);
1702 return (error);
1703}
1704
1705/*
1706 * nfs file create call
1707 * Mostly just call the approriate routine. (I separated out v4, so that
1708 * error recovery wouldn't be as difficult.)
1709 */
1710APPLESTATIC int
1711nfsrpc_create(vnode_t dvp, char *name, int namelen, struct vattr *vap,
1712 nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p,
1713 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
1714 int *attrflagp, int *dattrflagp, void *dstuff)
1715{
1716 int error = 0, newone, expireret = 0, retrycnt, unlocked;
1717 struct nfsclowner *owp;
1718 struct nfscldeleg *dp;
1719 struct nfsmount *nmp = VFSTONFS(vnode_mount(dvp));
1720 u_int32_t clidrev;
1721
1722 if (NFSHASNFSV4(nmp)) {
1723 retrycnt = 0;
1724 do {
1725 dp = NULL;
1726 error = nfscl_open(dvp, NULL, 0, (NFSV4OPEN_ACCESSWRITE |
1727 NFSV4OPEN_ACCESSREAD), 0, cred, p, &owp, NULL, &newone,
1728 NULL, 1);
1729 if (error)
1730 return (error);
1731 if (nmp->nm_clp != NULL)
1732 clidrev = nmp->nm_clp->nfsc_clientidrev;
1733 else
1734 clidrev = 0;
1735 error = nfsrpc_createv4(dvp, name, namelen, vap, cverf, fmode,
1736 owp, &dp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp,
1737 dstuff, &unlocked);
1738 /*
1739 * There is no need to invalidate cached attributes here,
1740 * since new post-delegation issue attributes are always
1741 * returned by nfsrpc_createv4() and these will update the
1742 * attribute cache.
1743 */
1744 if (dp != NULL)
1745 (void) nfscl_deleg(nmp->nm_mountp, owp->nfsow_clp,
1746 (*nfhpp)->nfh_fh, (*nfhpp)->nfh_len, cred, p, &dp);
1747 nfscl_ownerrelease(owp, error, newone, unlocked);
1748 if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
1749 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY) {
1750 (void) nfs_catnap(PZERO, error, "nfs_open");
1751 } else if ((error == NFSERR_EXPIRED ||
1752 error == NFSERR_BADSTATEID) && clidrev != 0) {
1753 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1754 retrycnt++;
1755 }
1756 } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
1757 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1758 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1759 expireret == 0 && clidrev != 0 && retrycnt < 4));
1760 if (error && retrycnt >= 4)
1761 error = EIO;
1762 } else {
1763 error = nfsrpc_createv23(dvp, name, namelen, vap, cverf,
1764 fmode, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp,
1765 dstuff);
1766 }
1767 return (error);
1768}
1769
1770/*
1771 * The create rpc for v2 and 3.
1772 */
1773static int
1774nfsrpc_createv23(vnode_t dvp, char *name, int namelen, struct vattr *vap,
1775 nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p,
1776 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
1777 int *attrflagp, int *dattrflagp, void *dstuff)
1778{
1779 u_int32_t *tl;
1780 int error = 0;
1781 struct nfsrv_descript nfsd, *nd = &nfsd;
1782
1783 *nfhpp = NULL;
1784 *attrflagp = 0;
1785 *dattrflagp = 0;
1786 if (namelen > NFS_MAXNAMLEN)
1787 return (ENAMETOOLONG);
1788 NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp);
1789 (void) nfsm_strtom(nd, name, namelen);
1790 if (nd->nd_flag & ND_NFSV3) {
1791 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1792 if (fmode & O_EXCL) {
1793 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE);
1794 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
1795 *tl++ = cverf.lval[0];
1796 *tl = cverf.lval[1];
1797 } else {
1798 *tl = txdr_unsigned(NFSCREATE_UNCHECKED);
1799 nfscl_fillsattr(nd, vap, dvp, 0, 0);
1800 }
1801 } else {
1802 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZE0, 0);
1803 }
1804 error = nfscl_request(nd, dvp, p, cred, dstuff);
1805 if (error)
1806 return (error);
1807 if (nd->nd_repstat == 0) {
1808 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
1809 if (error)
1810 goto nfsmout;
1811 }
1812 if (nd->nd_flag & ND_NFSV3)
1813 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
1814 if (nd->nd_repstat != 0 && error == 0)
1815 error = nd->nd_repstat;
1816nfsmout:
1817 mbuf_freem(nd->nd_mrep);
1818 return (error);
1819}
1820
1821static int
1822nfsrpc_createv4(vnode_t dvp, char *name, int namelen, struct vattr *vap,
1823 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp,
1824 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
1825 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
1826 int *dattrflagp, void *dstuff, int *unlockedp)
1827{
1828 u_int32_t *tl;
1829 int error = 0, deleg, newone, ret, acesize, limitby;
1830 struct nfsrv_descript nfsd, *nd = &nfsd;
1831 struct nfsclopen *op;
1832 struct nfscldeleg *dp = NULL;
1833 struct nfsnode *np;
1834 struct nfsfh *nfhp;
1835 nfsattrbit_t attrbits;
1836 nfsv4stateid_t stateid;
1837 u_int32_t rflags;
1838
1839 *unlockedp = 0;
1840 *nfhpp = NULL;
1841 *dpp = NULL;
1842 *attrflagp = 0;
1843 *dattrflagp = 0;
1844 if (namelen > NFS_MAXNAMLEN)
1845 return (ENAMETOOLONG);
1846 NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp);
1847 /*
1848 * For V4, this is actually an Open op.
1849 */
1850 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1851 *tl++ = txdr_unsigned(owp->nfsow_seqid);
1852 *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
1853 NFSV4OPEN_ACCESSREAD);
1854 *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE);
1855 *tl++ = owp->nfsow_clp->nfsc_clientid.lval[0];
1856 *tl = owp->nfsow_clp->nfsc_clientid.lval[1];
1857 (void) nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN);
1858 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1859 *tl++ = txdr_unsigned(NFSV4OPEN_CREATE);
1860 if (fmode & O_EXCL) {
1861 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE);
1862 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
1863 *tl++ = cverf.lval[0];
1864 *tl = cverf.lval[1];
1865 } else {
1866 *tl = txdr_unsigned(NFSCREATE_UNCHECKED);
1867 nfscl_fillsattr(nd, vap, dvp, 0, 0);
1868 }
1869 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1870 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
1871 (void) nfsm_strtom(nd, name, namelen);
1872 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1873 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
1874 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1875 NFSGETATTR_ATTRBIT(&attrbits);
1876 (void) nfsrv_putattrbit(nd, &attrbits);
1877 error = nfscl_request(nd, dvp, p, cred, dstuff);
1878 if (error)
1879 return (error);
1880 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
1881 if (error)
1882 goto nfsmout;
1883 NFSCL_INCRSEQID(owp->nfsow_seqid, nd);
1884 if (nd->nd_repstat == 0) {
1885 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
1886 6 * NFSX_UNSIGNED);
1887 stateid.seqid = *tl++;
1888 stateid.other[0] = *tl++;
1889 stateid.other[1] = *tl++;
1890 stateid.other[2] = *tl;
1891 rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
1892 (void) nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1893 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1894 deleg = fxdr_unsigned(int, *tl);
1895 if (deleg == NFSV4OPEN_DELEGATEREAD ||
1896 deleg == NFSV4OPEN_DELEGATEWRITE) {
1897 if (!(owp->nfsow_clp->nfsc_flags &
1898 NFSCLFLAGS_FIRSTDELEG))
1899 owp->nfsow_clp->nfsc_flags |=
1900 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
1901 MALLOC(dp, struct nfscldeleg *,
1902 sizeof (struct nfscldeleg) + NFSX_V4FHMAX,
1903 M_NFSCLDELEG, M_WAITOK);
1904 LIST_INIT(&dp->nfsdl_owner);
1905 LIST_INIT(&dp->nfsdl_lock);
1906 dp->nfsdl_clp = owp->nfsow_clp;
1907 newnfs_copyincred(cred, &dp->nfsdl_cred);
1908 nfscl_lockinit(&dp->nfsdl_rwlock);
1909 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
1910 NFSX_UNSIGNED);
1911 dp->nfsdl_stateid.seqid = *tl++;
1912 dp->nfsdl_stateid.other[0] = *tl++;
1913 dp->nfsdl_stateid.other[1] = *tl++;
1914 dp->nfsdl_stateid.other[2] = *tl++;
1915 ret = fxdr_unsigned(int, *tl);
1916 if (deleg == NFSV4OPEN_DELEGATEWRITE) {
1917 dp->nfsdl_flags = NFSCLDL_WRITE;
1918 /*
1919 * Indicates how much the file can grow.
1920 */
1921 NFSM_DISSECT(tl, u_int32_t *,
1922 3 * NFSX_UNSIGNED);
1923 limitby = fxdr_unsigned(int, *tl++);
1924 switch (limitby) {
1925 case NFSV4OPEN_LIMITSIZE:
1926 dp->nfsdl_sizelimit = fxdr_hyper(tl);
1927 break;
1928 case NFSV4OPEN_LIMITBLOCKS:
1929 dp->nfsdl_sizelimit =
1930 fxdr_unsigned(u_int64_t, *tl++);
1931 dp->nfsdl_sizelimit *=
1932 fxdr_unsigned(u_int64_t, *tl);
1933 break;
1934 default:
1935 error = NFSERR_BADXDR;
1936 goto nfsmout;
1937 };
1938 } else {
1939 dp->nfsdl_flags = NFSCLDL_READ;
1940 }
1941 if (ret)
1942 dp->nfsdl_flags |= NFSCLDL_RECALL;
1943 error = nfsrv_dissectace(nd, &dp->nfsdl_ace, &ret,
1944 &acesize, p);
1945 if (error)
1946 goto nfsmout;
1947 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
1948 error = NFSERR_BADXDR;
1949 goto nfsmout;
1950 }
1951 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
1952 if (error)
1953 goto nfsmout;
1954 if (dp != NULL && *attrflagp) {
1955 dp->nfsdl_change = nnap->na_filerev;
1956 dp->nfsdl_modtime = nnap->na_mtime;
1957 dp->nfsdl_flags |= NFSCLDL_MODTIMESET;
1958 }
1959 /*
1960 * We can now complete the Open state.
1961 */
1962 nfhp = *nfhpp;
1963 if (dp != NULL) {
1964 dp->nfsdl_fhlen = nfhp->nfh_len;
1965 NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, nfhp->nfh_len);
1966 }
1967 /*
1968 * Get an Open structure that will be
1969 * attached to the OpenOwner, acquired already.
1970 */
1971 error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len,
1972 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0,
1973 cred, p, NULL, &op, &newone, NULL, 0);
1974 if (error)
1975 goto nfsmout;
1976 op->nfso_stateid = stateid;
1977 newnfs_copyincred(cred, &op->nfso_cred);
1978 if ((rflags & NFSV4OPEN_RESULTCONFIRM)) {
1979 do {
1980 ret = nfsrpc_openconfirm(dvp, nfhp->nfh_fh,
1981 nfhp->nfh_len, op, cred, p);
1982 if (ret == NFSERR_DELAY)
1983 (void) nfs_catnap(PZERO, ret, "nfs_create");
1984 } while (ret == NFSERR_DELAY);
1985 error = ret;
1986 }
1987
1988 /*
1989 * If the server is handing out delegations, but we didn't
1990 * get one because an OpenConfirm was required, try the
1991 * Open again, to get a delegation. This is a harmless no-op,
1992 * from a server's point of view.
1993 */
1994 if ((rflags & NFSV4OPEN_RESULTCONFIRM) &&
1995 (owp->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) &&
1996 !error && dp == NULL) {
1997 np = VTONFS(dvp);
1998 do {
1999 ret = nfsrpc_openrpc(VFSTONFS(vnode_mount(dvp)), dvp,
2000 np->n_fhp->nfh_fh, np->n_fhp->nfh_len,
2001 nfhp->nfh_fh, nfhp->nfh_len,
2002 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), op,
2003 name, namelen, &dp, 0, 0x0, cred, p, 0, 1);
2004 if (ret == NFSERR_DELAY)
2005 (void) nfs_catnap(PZERO, ret, "nfs_crt2");
2006 } while (ret == NFSERR_DELAY);
2007 if (ret) {
2008 if (dp != NULL)
2009 FREE((caddr_t)dp, M_NFSCLDELEG);
2010 if (ret == NFSERR_STALECLIENTID ||
2011 ret == NFSERR_STALEDONTRECOVER)
2012 error = ret;
2013 }
2014 }
2015 nfscl_openrelease(op, error, newone);
2016 *unlockedp = 1;
2017 }
2018 if (nd->nd_repstat != 0 && error == 0)
2019 error = nd->nd_repstat;
2020 if (error == NFSERR_STALECLIENTID)
2021 nfscl_initiate_recovery(owp->nfsow_clp);
2022nfsmout:
2023 if (!error)
2024 *dpp = dp;
2025 else if (dp != NULL)
2026 FREE((caddr_t)dp, M_NFSCLDELEG);
2027 mbuf_freem(nd->nd_mrep);
2028 return (error);
2029}
2030
2031/*
2032 * Nfs remove rpc
2033 */
2034APPLESTATIC int
2035nfsrpc_remove(vnode_t dvp, char *name, int namelen, vnode_t vp,
2036 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp,
2037 void *dstuff)
2038{
2039 u_int32_t *tl;
2040 struct nfsrv_descript nfsd, *nd = &nfsd;
2041 struct nfsnode *np;
2042 struct nfsmount *nmp;
2043 nfsv4stateid_t dstateid;
2044 int error, ret = 0, i;
2045
2046 *dattrflagp = 0;
2047 if (namelen > NFS_MAXNAMLEN)
2048 return (ENAMETOOLONG);
2049 nmp = VFSTONFS(vnode_mount(dvp));
2050tryagain:
2051 if (NFSHASNFSV4(nmp) && ret == 0) {
2052 ret = nfscl_removedeleg(vp, p, &dstateid);
2053 if (ret == 1) {
2054 NFSCL_REQSTART(nd, NFSPROC_RETDELEGREMOVE, vp);
2055 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID +
2056 NFSX_UNSIGNED);
2057 *tl++ = dstateid.seqid;
2058 *tl++ = dstateid.other[0];
2059 *tl++ = dstateid.other[1];
2060 *tl++ = dstateid.other[2];
2061 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2062 np = VTONFS(dvp);
2063 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
2064 np->n_fhp->nfh_len, 0);
2065 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2066 *tl = txdr_unsigned(NFSV4OP_REMOVE);
2067 }
2068 } else {
2069 ret = 0;
2070 }
2071 if (ret == 0)
2072 NFSCL_REQSTART(nd, NFSPROC_REMOVE, dvp);
2073 (void) nfsm_strtom(nd, name, namelen);
2074 error = nfscl_request(nd, dvp, p, cred, dstuff);
2075 if (error)
2076 return (error);
2077 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
2078 /* For NFSv4, parse out any Delereturn replies. */
2079 if (ret > 0 && nd->nd_repstat != 0 &&
2080 (nd->nd_flag & ND_NOMOREDATA)) {
2081 /*
2082 * If the Delegreturn failed, try again without
2083 * it. The server will Recall, as required.
2084 */
2085 mbuf_freem(nd->nd_mrep);
2086 goto tryagain;
2087 }
2088 for (i = 0; i < (ret * 2); i++) {
2089 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
2090 ND_NFSV4) {
2091 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2092 if (*(tl + 1))
2093 nd->nd_flag |= ND_NOMOREDATA;
2094 }
2095 }
2096 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2097 }
2098 if (nd->nd_repstat && !error)
2099 error = nd->nd_repstat;
2100nfsmout:
2101 mbuf_freem(nd->nd_mrep);
2102 return (error);
2103}
2104
2105/*
2106 * Do an nfs rename rpc.
2107 */
2108APPLESTATIC int
2109nfsrpc_rename(vnode_t fdvp, vnode_t fvp, char *fnameptr, int fnamelen,
2110 vnode_t tdvp, vnode_t tvp, char *tnameptr, int tnamelen, struct ucred *cred,
2111 NFSPROC_T *p, struct nfsvattr *fnap, struct nfsvattr *tnap,
2112 int *fattrflagp, int *tattrflagp, void *fstuff, void *tstuff)
2113{
2114 u_int32_t *tl;
2115 struct nfsrv_descript nfsd, *nd = &nfsd;
2116 struct nfsmount *nmp;
2117 struct nfsnode *np;
2118 nfsattrbit_t attrbits;
2119 nfsv4stateid_t fdstateid, tdstateid;
2120 int error = 0, ret = 0, gottd = 0, gotfd = 0, i;
2121
2122 *fattrflagp = 0;
2123 *tattrflagp = 0;
2124 nmp = VFSTONFS(vnode_mount(fdvp));
2125 if (fnamelen > NFS_MAXNAMLEN || tnamelen > NFS_MAXNAMLEN)
2126 return (ENAMETOOLONG);
2127tryagain:
2128 if (NFSHASNFSV4(nmp) && ret == 0) {
2129 ret = nfscl_renamedeleg(fvp, &fdstateid, &gotfd, tvp,
2130 &tdstateid, &gottd, p);
2131 if (gotfd && gottd) {
2132 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME2, fvp);
2133 } else if (gotfd) {
2134 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, fvp);
2135 } else if (gottd) {
2136 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, tvp);
2137 }
2138 if (gotfd) {
2139 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2140 *tl++ = fdstateid.seqid;
2141 *tl++ = fdstateid.other[0];
2142 *tl++ = fdstateid.other[1];
2143 *tl = fdstateid.other[2];
2144 if (gottd) {
2145 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2146 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2147 np = VTONFS(tvp);
2148 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
2149 np->n_fhp->nfh_len, 0);
2150 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2151 *tl = txdr_unsigned(NFSV4OP_DELEGRETURN);
2152 }
2153 }
2154 if (gottd) {
2155 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2156 *tl++ = tdstateid.seqid;
2157 *tl++ = tdstateid.other[0];
2158 *tl++ = tdstateid.other[1];
2159 *tl = tdstateid.other[2];
2160 }
2161 if (ret > 0) {
2162 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2163 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2164 np = VTONFS(fdvp);
2165 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
2166 np->n_fhp->nfh_len, 0);
2167 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2168 *tl = txdr_unsigned(NFSV4OP_SAVEFH);
2169 }
2170 } else {
2171 ret = 0;
2172 }
2173 if (ret == 0)
2174 NFSCL_REQSTART(nd, NFSPROC_RENAME, fdvp);
2175 if (nd->nd_flag & ND_NFSV4) {
2176 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2177 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2178 NFSWCCATTR_ATTRBIT(&attrbits);
2179 (void) nfsrv_putattrbit(nd, &attrbits);
2180 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2181 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2182 (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh,
2183 VTONFS(tdvp)->n_fhp->nfh_len, 0);
2184 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2185 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2186 (void) nfsrv_putattrbit(nd, &attrbits);
2187 nd->nd_flag |= ND_V4WCCATTR;
2188 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2189 *tl = txdr_unsigned(NFSV4OP_RENAME);
2190 }
2191 (void) nfsm_strtom(nd, fnameptr, fnamelen);
2192 if (!(nd->nd_flag & ND_NFSV4))
2193 (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh,
2194 VTONFS(tdvp)->n_fhp->nfh_len, 0);
2195 (void) nfsm_strtom(nd, tnameptr, tnamelen);
2196 error = nfscl_request(nd, fdvp, p, cred, fstuff);
2197 if (error)
2198 return (error);
2199 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
2200 /* For NFSv4, parse out any Delereturn replies. */
2201 if (ret > 0 && nd->nd_repstat != 0 &&
2202 (nd->nd_flag & ND_NOMOREDATA)) {
2203 /*
2204 * If the Delegreturn failed, try again without
2205 * it. The server will Recall, as required.
2206 */
2207 mbuf_freem(nd->nd_mrep);
2208 goto tryagain;
2209 }
2210 for (i = 0; i < (ret * 2); i++) {
2211 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
2212 ND_NFSV4) {
2213 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2214 if (*(tl + 1)) {
2215 if (i == 0 && ret > 1) {
2216 /*
2217 * If the Delegreturn failed, try again
2218 * without it. The server will Recall, as
2219 * required.
2220 * If ret > 1, the first iteration of this
2221 * loop is the second DelegReturn result.
2222 */
2223 mbuf_freem(nd->nd_mrep);
2224 goto tryagain;
2225 } else {
2226 nd->nd_flag |= ND_NOMOREDATA;
2227 }
2228 }
2229 }
2230 }
2231 /* Now, the first wcc attribute reply. */
2232 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
2233 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2234 if (*(tl + 1))
2235 nd->nd_flag |= ND_NOMOREDATA;
2236 }
2237 error = nfscl_wcc_data(nd, fdvp, fnap, fattrflagp, NULL,
2238 fstuff);
2239 /* and the second wcc attribute reply. */
2240 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 &&
2241 !error) {
2242 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2243 if (*(tl + 1))
2244 nd->nd_flag |= ND_NOMOREDATA;
2245 }
2246 if (!error)
2247 error = nfscl_wcc_data(nd, tdvp, tnap, tattrflagp,
2248 NULL, tstuff);
2249 }
2250 if (nd->nd_repstat && !error)
2251 error = nd->nd_repstat;
2252nfsmout:
2253 mbuf_freem(nd->nd_mrep);
2254 return (error);
2255}
2256
2257/*
2258 * nfs hard link create rpc
2259 */
2260APPLESTATIC int
2261nfsrpc_link(vnode_t dvp, vnode_t vp, char *name, int namelen,
2262 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
2263 struct nfsvattr *nap, int *attrflagp, int *dattrflagp, void *dstuff)
2264{
2265 u_int32_t *tl;
2266 struct nfsrv_descript nfsd, *nd = &nfsd;
2267 nfsattrbit_t attrbits;
2268 int error = 0;
2269
2270 *attrflagp = 0;
2271 *dattrflagp = 0;
2272 if (namelen > NFS_MAXNAMLEN)
2273 return (ENAMETOOLONG);
2274 NFSCL_REQSTART(nd, NFSPROC_LINK, vp);
2275 if (nd->nd_flag & ND_NFSV4) {
2276 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2277 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2278 }
2279 (void) nfsm_fhtom(nd, VTONFS(dvp)->n_fhp->nfh_fh,
2280 VTONFS(dvp)->n_fhp->nfh_len, 0);
2281 if (nd->nd_flag & ND_NFSV4) {
2282 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2283 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2284 NFSWCCATTR_ATTRBIT(&attrbits);
2285 (void) nfsrv_putattrbit(nd, &attrbits);
2286 nd->nd_flag |= ND_V4WCCATTR;
2287 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2288 *tl = txdr_unsigned(NFSV4OP_LINK);
2289 }
2290 (void) nfsm_strtom(nd, name, namelen);
2291 error = nfscl_request(nd, vp, p, cred, dstuff);
2292 if (error)
2293 return (error);
2294 if (nd->nd_flag & ND_NFSV3) {
2295 error = nfscl_postop_attr(nd, nap, attrflagp, dstuff);
2296 if (!error)
2297 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp,
2298 NULL, dstuff);
2299 } else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
2300 /*
2301 * First, parse out the PutFH and Getattr result.
2302 */
2303 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2304 if (!(*(tl + 1)))
2305 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2306 if (*(tl + 1))
2307 nd->nd_flag |= ND_NOMOREDATA;
2308 /*
2309 * Get the pre-op attributes.
2310 */
2311 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2312 }
2313 if (nd->nd_repstat && !error)
2314 error = nd->nd_repstat;
2315nfsmout:
2316 mbuf_freem(nd->nd_mrep);
2317 return (error);
2318}
2319
2320/*
2321 * nfs symbolic link create rpc
2322 */
2323APPLESTATIC int
2324nfsrpc_symlink(vnode_t dvp, char *name, int namelen, char *target,
2325 struct vattr *vap, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
2326 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
2327 int *dattrflagp, void *dstuff)
2328{
2329 u_int32_t *tl;
2330 struct nfsrv_descript nfsd, *nd = &nfsd;
2331 struct nfsmount *nmp;
2332 int slen, error = 0;
2333
2334 *nfhpp = NULL;
2335 *attrflagp = 0;
2336 *dattrflagp = 0;
2337 nmp = VFSTONFS(vnode_mount(dvp));
2338 slen = strlen(target);
2339 if (slen > NFS_MAXPATHLEN || namelen > NFS_MAXNAMLEN)
2340 return (ENAMETOOLONG);
2341 NFSCL_REQSTART(nd, NFSPROC_SYMLINK, dvp);
2342 if (nd->nd_flag & ND_NFSV4) {
2343 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2344 *tl = txdr_unsigned(NFLNK);
2345 (void) nfsm_strtom(nd, target, slen);
2346 }
2347 (void) nfsm_strtom(nd, name, namelen);
2348 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
2349 nfscl_fillsattr(nd, vap, dvp, 0, 0);
2350 if (!(nd->nd_flag & ND_NFSV4))
2351 (void) nfsm_strtom(nd, target, slen);
2352 if (nd->nd_flag & ND_NFSV2)
2353 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0);
2354 error = nfscl_request(nd, dvp, p, cred, dstuff);
2355 if (error)
2356 return (error);
2357 if (nd->nd_flag & ND_NFSV4)
2358 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2359 if ((nd->nd_flag & ND_NFSV3) && !error) {
2360 if (!nd->nd_repstat)
2361 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
2362 if (!error)
2363 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp,
2364 NULL, dstuff);
2365 }
2366 if (nd->nd_repstat && !error)
2367 error = nd->nd_repstat;
2368 mbuf_freem(nd->nd_mrep);
2369 /*
2370 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
2371 */
2372 if (error == EEXIST)
2373 error = 0;
2374 return (error);
2375}
2376
2377/*
2378 * nfs make dir rpc
2379 */
2380APPLESTATIC int
2381nfsrpc_mkdir(vnode_t dvp, char *name, int namelen, struct vattr *vap,
2382 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
2383 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
2384 int *dattrflagp, void *dstuff)
2385{
2386 u_int32_t *tl;
2387 struct nfsrv_descript nfsd, *nd = &nfsd;
2388 nfsattrbit_t attrbits;
2389 int error = 0;
2390
2391 *nfhpp = NULL;
2392 *attrflagp = 0;
2393 *dattrflagp = 0;
2394 if (namelen > NFS_MAXNAMLEN)
2395 return (ENAMETOOLONG);
2396 NFSCL_REQSTART(nd, NFSPROC_MKDIR, dvp);
2397 if (nd->nd_flag & ND_NFSV4) {
2398 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2399 *tl = txdr_unsigned(NFDIR);
2400 }
2401 (void) nfsm_strtom(nd, name, namelen);
2402 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0);
2403 if (nd->nd_flag & ND_NFSV4) {
2404 NFSGETATTR_ATTRBIT(&attrbits);
2405 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2406 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
2407 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2408 (void) nfsrv_putattrbit(nd, &attrbits);
2409 }
2410 error = nfscl_request(nd, dvp, p, cred, dstuff);
2411 if (error)
2412 return (error);
2413 if (nd->nd_flag & ND_NFSV4)
2414 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2415 if (!nd->nd_repstat && !error) {
2416 if (nd->nd_flag & ND_NFSV4) {
2417 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2418 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
2419 }
2420 if (!error)
2421 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
2422 }
2423 if ((nd->nd_flag & ND_NFSV3) && !error)
2424 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2425 if (nd->nd_repstat && !error)
2426 error = nd->nd_repstat;
2427nfsmout:
2428 mbuf_freem(nd->nd_mrep);
2429 /*
2430 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry.
2431 */
2432 if (error == EEXIST)
2433 error = 0;
2434 return (error);
2435}
2436
2437/*
2438 * nfs remove directory call
2439 */
2440APPLESTATIC int
2441nfsrpc_rmdir(vnode_t dvp, char *name, int namelen, struct ucred *cred,
2442 NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp, void *dstuff)
2443{
2444 struct nfsrv_descript nfsd, *nd = &nfsd;
2445 int error = 0;
2446
2447 *dattrflagp = 0;
2448 if (namelen > NFS_MAXNAMLEN)
2449 return (ENAMETOOLONG);
2450 NFSCL_REQSTART(nd, NFSPROC_RMDIR, dvp);
2451 (void) nfsm_strtom(nd, name, namelen);
2452 error = nfscl_request(nd, dvp, p, cred, dstuff);
2453 if (error)
2454 return (error);
2455 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
2456 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
2457 if (nd->nd_repstat && !error)
2458 error = nd->nd_repstat;
2459 mbuf_freem(nd->nd_mrep);
2460 /*
2461 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
2462 */
2463 if (error == ENOENT)
2464 error = 0;
2465 return (error);
2466}
2467
2468/*
2469 * Readdir rpc.
2470 * Always returns with either uio_resid unchanged, if you are at the
2471 * end of the directory, or uio_resid == 0, with all DIRBLKSIZ chunks
2472 * filled in.
2473 * I felt this would allow caching of directory blocks more easily
2474 * than returning a pertially filled block.
2475 * Directory offset cookies:
2476 * Oh my, what to do with them...
2477 * I can think of three ways to deal with them:
2478 * 1 - have the layer above these RPCs maintain a map between logical
2479 * directory byte offsets and the NFS directory offset cookies
2480 * 2 - pass the opaque directory offset cookies up into userland
2481 * and let the libc functions deal with them, via the system call
2482 * 3 - return them to userland in the "struct dirent", so future versions
2483 * of libc can use them and do whatever is necessary to amke things work
2484 * above these rpc calls, in the meantime
2485 * For now, I do #3 by "hiding" the directory offset cookies after the
2486 * d_name field in struct dirent. This is space inside d_reclen that
2487 * will be ignored by anything that doesn't know about them.
2488 * The directory offset cookies are filled in as the last 8 bytes of
2489 * each directory entry, after d_name. Someday, the userland libc
2490 * functions may be able to use these. In the meantime, it satisfies
2491 * OpenBSD's requirements for cookies being returned.
2492 * If expects the directory offset cookie for the read to be in uio_offset
2493 * and returns the one for the next entry after this directory block in
2494 * there, as well.
2495 */
2496APPLESTATIC int
2497nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
2498 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
2499 int *eofp, void *stuff)
2500{
2501 int len, left;
2502 struct dirent *dp = NULL;
2503 u_int32_t *tl;
2504 nfsquad_t cookie, ncookie;
2505 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
2506 struct nfsnode *dnp = VTONFS(vp);
2507 struct nfsvattr nfsva;
2508 struct nfsrv_descript nfsd, *nd = &nfsd;
2509 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
2510 int reqsize, tryformoredirs = 1, readsize, eof = 0, gotmnton = 0;
2511 long dotfileid, dotdotfileid = 0;
2512 u_int32_t fakefileno = 0xffffffff, rderr;
2513 char *cp;
2514 nfsattrbit_t attrbits, dattrbits;
2515 u_int32_t *tl2 = NULL;
2516 size_t tresid;
2517
2518 KASSERT(uiop->uio_iovcnt == 1 &&
2519 (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0,
2520 ("nfs readdirrpc bad uio"));
2521
2522 /*
2523 * There is no point in reading a lot more than uio_resid, however
2524 * adding one additional DIRBLKSIZ makes sense. Since uio_resid
2525 * and nm_readdirsize are both exact multiples of DIRBLKSIZ, this
2526 * will never make readsize > nm_readdirsize.
2527 */
2528 readsize = nmp->nm_readdirsize;
2529 if (readsize > uio_uio_resid(uiop))
2530 readsize = uio_uio_resid(uiop) + DIRBLKSIZ;
2531
2532 *attrflagp = 0;
2533 if (eofp)
2534 *eofp = 0;
2535 tresid = uio_uio_resid(uiop);
2536 cookie.lval[0] = cookiep->nfsuquad[0];
2537 cookie.lval[1] = cookiep->nfsuquad[1];
2538 nd->nd_mrep = NULL;
2539
2540 /*
2541 * For NFSv4, first create the "." and ".." entries.
2542 */
2543 if (NFSHASNFSV4(nmp)) {
2544 reqsize = 6 * NFSX_UNSIGNED;
2545 NFSGETATTR_ATTRBIT(&dattrbits);
2546 NFSZERO_ATTRBIT(&attrbits);
2547 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID);
2548 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TYPE);
2549 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
2550 NFSATTRBIT_MOUNTEDONFILEID)) {
2551 NFSSETBIT_ATTRBIT(&attrbits,
2552 NFSATTRBIT_MOUNTEDONFILEID);
2553 gotmnton = 1;
2554 } else {
2555 /*
2556 * Must fake it. Use the fileno, except when the
2557 * fsid is != to that of the directory. For that
2558 * case, generate a fake fileno that is not the same.
2559 */
2560 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID);
2561 gotmnton = 0;
2562 }
2563
2564 /*
2565 * Joy, oh joy. For V4 we get to hand craft '.' and '..'.
2566 */
2567 if (uiop->uio_offset == 0) {
2568#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000
2569 error = VOP_GETATTR(vp, &nfsva.na_vattr, cred);
2570#else
2571 error = VOP_GETATTR(vp, &nfsva.na_vattr, cred, p);
2572#endif
2573 if (error)
2574 return (error);
2575 dotfileid = nfsva.na_fileid;
2576 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp);
2577 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2578 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
2579 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2580 (void) nfsrv_putattrbit(nd, &attrbits);
2581 error = nfscl_request(nd, vp, p, cred, stuff);
2582 if (error)
2583 return (error);
2584 if (nd->nd_repstat == 0) {
2585 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
2586 len = fxdr_unsigned(int, *(tl + 2));
2587 if (len > 0 && len <= NFSX_V4FHMAX)
2588 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
2589 else
2590 error = EPERM;
2591 if (!error) {
2592 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
2593 nfsva.na_mntonfileno = 0xffffffff;
2594 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
2595 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
2596 NULL, NULL, NULL, p, cred);
2597 if (error) {
2598 dotdotfileid = dotfileid;
2599 } else if (gotmnton) {
2600 if (nfsva.na_mntonfileno != 0xffffffff)
2601 dotdotfileid = nfsva.na_mntonfileno;
2602 else
2603 dotdotfileid = nfsva.na_fileid;
2604 } else if (nfsva.na_filesid[0] ==
2605 dnp->n_vattr.na_filesid[0] &&
2606 nfsva.na_filesid[1] ==
2607 dnp->n_vattr.na_filesid[1]) {
2608 dotdotfileid = nfsva.na_fileid;
2609 } else {
2610 do {
2611 fakefileno--;
2612 } while (fakefileno ==
2613 nfsva.na_fileid);
2614 dotdotfileid = fakefileno;
2615 }
2616 }
2617 } else if (nd->nd_repstat == NFSERR_NOENT) {
2618 /*
2619 * Lookupp returns NFSERR_NOENT when we are
2620 * at the root, so just use the current dir.
2621 */
2622 nd->nd_repstat = 0;
2623 dotdotfileid = dotfileid;
2624 } else {
2625 error = nd->nd_repstat;
2626 }
2627 mbuf_freem(nd->nd_mrep);
2628 if (error)
2629 return (error);
2630 nd->nd_mrep = NULL;
2631 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
2632 dp->d_type = DT_DIR;
2633 dp->d_fileno = dotfileid;
2634 dp->d_namlen = 1;
2635 dp->d_name[0] = '.';
2636 dp->d_name[1] = '\0';
2637 dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
2638 /*
2639 * Just make these offset cookie 0.
2640 */
2641 tl = (u_int32_t *)&dp->d_name[4];
2642 *tl++ = 0;
2643 *tl = 0;
2644 blksiz += dp->d_reclen;
2645 uio_uio_resid_add(uiop, -(dp->d_reclen));
2646 uiop->uio_offset += dp->d_reclen;
2647 uio_iov_base_add(uiop, dp->d_reclen);
2648 uio_iov_len_add(uiop, -(dp->d_reclen));
2649 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
2650 dp->d_type = DT_DIR;
2651 dp->d_fileno = dotdotfileid;
2652 dp->d_namlen = 2;
2653 dp->d_name[0] = '.';
2654 dp->d_name[1] = '.';
2655 dp->d_name[2] = '\0';
2656 dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
2657 /*
2658 * Just make these offset cookie 0.
2659 */
2660 tl = (u_int32_t *)&dp->d_name[4];
2661 *tl++ = 0;
2662 *tl = 0;
2663 blksiz += dp->d_reclen;
2664 uio_uio_resid_add(uiop, -(dp->d_reclen));
2665 uiop->uio_offset += dp->d_reclen;
2666 uio_iov_base_add(uiop, dp->d_reclen);
2667 uio_iov_len_add(uiop, -(dp->d_reclen));
2668 }
2669 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_RDATTRERROR);
2670 } else {
2671 reqsize = 5 * NFSX_UNSIGNED;
2672 }
2673
2674
2675 /*
2676 * Loop around doing readdir rpc's of size readsize.
2677 * The stopping criteria is EOF or buffer full.
2678 */
2679 while (more_dirs && bigenough) {
2680 *attrflagp = 0;
2681 NFSCL_REQSTART(nd, NFSPROC_READDIR, vp);
2682 if (nd->nd_flag & ND_NFSV2) {
2683 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2684 *tl++ = cookie.lval[1];
2685 *tl = txdr_unsigned(readsize);
2686 } else {
2687 NFSM_BUILD(tl, u_int32_t *, reqsize);
2688 *tl++ = cookie.lval[0];
2689 *tl++ = cookie.lval[1];
2690 if (cookie.qval == 0) {
2691 *tl++ = 0;
2692 *tl++ = 0;
2693 } else {
2694 NFSLOCKNODE(dnp);
2695 *tl++ = dnp->n_cookieverf.nfsuquad[0];
2696 *tl++ = dnp->n_cookieverf.nfsuquad[1];
2697 NFSUNLOCKNODE(dnp);
2698 }
2699 if (nd->nd_flag & ND_NFSV4) {
2700 *tl++ = txdr_unsigned(readsize);
2701 *tl = txdr_unsigned(readsize);
2702 (void) nfsrv_putattrbit(nd, &attrbits);
2703 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2704 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2705 (void) nfsrv_putattrbit(nd, &dattrbits);
2706 } else {
2707 *tl = txdr_unsigned(readsize);
2708 }
2709 }
2710 error = nfscl_request(nd, vp, p, cred, stuff);
2711 if (error)
2712 return (error);
2713 if (!(nd->nd_flag & ND_NFSV2)) {
2714 if (nd->nd_flag & ND_NFSV3)
2715 error = nfscl_postop_attr(nd, nap, attrflagp,
2716 stuff);
2717 if (!nd->nd_repstat && !error) {
2718 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2719 NFSLOCKNODE(dnp);
2720 dnp->n_cookieverf.nfsuquad[0] = *tl++;
2721 dnp->n_cookieverf.nfsuquad[1] = *tl;
2722 NFSUNLOCKNODE(dnp);
2723 }
2724 }
2725 if (nd->nd_repstat || error) {
2726 if (!error)
2727 error = nd->nd_repstat;
2728 goto nfsmout;
2729 }
2730 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2731 more_dirs = fxdr_unsigned(int, *tl);
2732 if (!more_dirs)
2733 tryformoredirs = 0;
2734
2735 /* loop thru the dir entries, doctoring them to 4bsd form */
2736 while (more_dirs && bigenough) {
2737 if (nd->nd_flag & ND_NFSV4) {
2738 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
2739 ncookie.lval[0] = *tl++;
2740 ncookie.lval[1] = *tl++;
2741 len = fxdr_unsigned(int, *tl);
2742 } else if (nd->nd_flag & ND_NFSV3) {
2743 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
2744 nfsva.na_fileid = fxdr_hyper(tl);
2745 tl += 2;
2746 len = fxdr_unsigned(int, *tl);
2747 } else {
2748 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
2749 nfsva.na_fileid =
2750 fxdr_unsigned(long, *tl++);
2751 len = fxdr_unsigned(int, *tl);
2752 }
2753 if (len <= 0 || len > NFS_MAXNAMLEN) {
2754 error = EBADRPC;
2755 goto nfsmout;
2756 }
2757 tlen = NFSM_RNDUP(len);
2758 if (tlen == len)
2759 tlen += 4; /* To ensure null termination */
2760 left = DIRBLKSIZ - blksiz;
2761 if ((int)(tlen + DIRHDSIZ + NFSX_HYPER) > left) {
2762 dp->d_reclen += left;
2763 uio_iov_base_add(uiop, left);
2764 uio_iov_len_add(uiop, -(left));
2765 uio_uio_resid_add(uiop, -(left));
2766 uiop->uio_offset += left;
2767 blksiz = 0;
2768 }
2769 if ((int)(tlen + DIRHDSIZ + NFSX_HYPER) > uio_uio_resid(uiop))
2770 bigenough = 0;
2771 if (bigenough) {
2772 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
2773 dp->d_namlen = len;
2774 dp->d_reclen = tlen + DIRHDSIZ + NFSX_HYPER;
2775 dp->d_type = DT_UNKNOWN;
2776 blksiz += dp->d_reclen;
2777 if (blksiz == DIRBLKSIZ)
2778 blksiz = 0;
2779 uio_uio_resid_add(uiop, -(DIRHDSIZ));
2780 uiop->uio_offset += DIRHDSIZ;
2781 uio_iov_base_add(uiop, DIRHDSIZ);
2782 uio_iov_len_add(uiop, -(DIRHDSIZ));
2783 error = nfsm_mbufuio(nd, uiop, len);
2784 if (error)
2785 goto nfsmout;
2786 cp = CAST_DOWN(caddr_t, uio_iov_base(uiop));
2787 tlen -= len;
2788 *cp = '\0'; /* null terminate */
2789 cp += tlen; /* points to cookie storage */
2790 tl2 = (u_int32_t *)cp;
2791 uio_iov_base_add(uiop, (tlen + NFSX_HYPER));
2792 uio_iov_len_add(uiop, -(tlen + NFSX_HYPER));
2793 uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER));
2794 uiop->uio_offset += (tlen + NFSX_HYPER);
2795 } else {
2796 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
2797 if (error)
2798 goto nfsmout;
2799 }
2800 if (nd->nd_flag & ND_NFSV4) {
2801 rderr = 0;
2802 nfsva.na_mntonfileno = 0xffffffff;
2803 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
2804 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
2805 NULL, NULL, &rderr, p, cred);
2806 if (error)
2807 goto nfsmout;
2808 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2809 } else if (nd->nd_flag & ND_NFSV3) {
2810 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
2811 ncookie.lval[0] = *tl++;
2812 ncookie.lval[1] = *tl++;
2813 } else {
2814 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
2815 ncookie.lval[0] = 0;
2816 ncookie.lval[1] = *tl++;
2817 }
2818 if (bigenough) {
2819 if (nd->nd_flag & ND_NFSV4) {
2820 if (rderr) {
2821 dp->d_fileno = 0;
2822 } else {
2823 if (gotmnton) {
2824 if (nfsva.na_mntonfileno != 0xffffffff)
2825 dp->d_fileno = nfsva.na_mntonfileno;
2826 else
2827 dp->d_fileno = nfsva.na_fileid;
2828 } else if (nfsva.na_filesid[0] ==
2829 dnp->n_vattr.na_filesid[0] &&
2830 nfsva.na_filesid[1] ==
2831 dnp->n_vattr.na_filesid[1]) {
2832 dp->d_fileno = nfsva.na_fileid;
2833 } else {
2834 do {
2835 fakefileno--;
2836 } while (fakefileno ==
2837 nfsva.na_fileid);
2838 dp->d_fileno = fakefileno;
2839 }
2840 dp->d_type = vtonfs_dtype(nfsva.na_type);
2841 }
2842 } else {
2843 dp->d_fileno = nfsva.na_fileid;
2844 }
2845 *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] =
2846 ncookie.lval[0];
2847 *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] =
2848 ncookie.lval[1];
2849 }
2850 more_dirs = fxdr_unsigned(int, *tl);
2851 }
2852 /*
2853 * If at end of rpc data, get the eof boolean
2854 */
2855 if (!more_dirs) {
2856 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2857 eof = fxdr_unsigned(int, *tl);
2858 if (tryformoredirs)
2859 more_dirs = !eof;
2860 if (nd->nd_flag & ND_NFSV4) {
2861 error = nfscl_postop_attr(nd, nap, attrflagp,
2862 stuff);
2863 if (error)
2864 goto nfsmout;
2865 }
2866 }
2867 mbuf_freem(nd->nd_mrep);
2868 nd->nd_mrep = NULL;
2869 }
2870 /*
2871 * Fill last record, iff any, out to a multiple of DIRBLKSIZ
2872 * by increasing d_reclen for the last record.
2873 */
2874 if (blksiz > 0) {
2875 left = DIRBLKSIZ - blksiz;
2876 dp->d_reclen += left;
2877 uio_iov_base_add(uiop, left);
2878 uio_iov_len_add(uiop, -(left));
2879 uio_uio_resid_add(uiop, -(left));
2880 uiop->uio_offset += left;
2881 }
2882
2883 /*
2884 * If returning no data, assume end of file.
2885 * If not bigenough, return not end of file, since you aren't
2886 * returning all the data
2887 * Otherwise, return the eof flag from the server.
2888 */
2889 if (eofp) {
2890 if (tresid == ((size_t)(uio_uio_resid(uiop))))
2891 *eofp = 1;
2892 else if (!bigenough)
2893 *eofp = 0;
2894 else
2895 *eofp = eof;
2896 }
2897
2898 /*
2899 * Add extra empty records to any remaining DIRBLKSIZ chunks.
2900 */
2901 while (uio_uio_resid(uiop) > 0 && ((size_t)(uio_uio_resid(uiop))) != tresid) {
2902 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
2903 dp->d_type = DT_UNKNOWN;
2904 dp->d_fileno = 0;
2905 dp->d_namlen = 0;
2906 dp->d_name[0] = '\0';
2907 tl = (u_int32_t *)&dp->d_name[4];
2908 *tl++ = cookie.lval[0];
2909 *tl = cookie.lval[1];
2910 dp->d_reclen = DIRBLKSIZ;
2911 uio_iov_base_add(uiop, DIRBLKSIZ);
2912 uio_iov_len_add(uiop, -(DIRBLKSIZ));
2913 uio_uio_resid_add(uiop, -(DIRBLKSIZ));
2914 uiop->uio_offset += DIRBLKSIZ;
2915 }
2916
2917nfsmout:
2918 if (nd->nd_mrep != NULL)
2919 mbuf_freem(nd->nd_mrep);
2920 return (error);
2921}
2922
2923#ifndef APPLE
2924/*
2925 * NFS V3 readdir plus RPC. Used in place of nfsrpc_readdir().
2926 * (Also used for NFS V4 when mount flag set.)
2927 * (ditto above w.r.t. multiple of DIRBLKSIZ, etc.)
2928 */
2929APPLESTATIC int
2930nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
2931 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
2932 int *eofp, void *stuff)
2933{
2934 int len, left;
2935 struct dirent *dp = NULL;
2936 u_int32_t *tl;
2937 vnode_t newvp = NULLVP;
2938 struct nfsrv_descript nfsd, *nd = &nfsd;
2939 struct nameidata nami, *ndp = &nami;
2940 struct componentname *cnp = &ndp->ni_cnd;
2941 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
2942 struct nfsnode *dnp = VTONFS(vp), *np;
2943 struct nfsvattr nfsva;
2944 struct nfsfh *nfhp;
2945 nfsquad_t cookie, ncookie;
2946 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
2947 int attrflag, tryformoredirs = 1, eof = 0, gotmnton = 0;
2948 int isdotdot = 0, unlocknewvp = 0;
2949 long dotfileid, dotdotfileid = 0, fileno = 0;
2950 char *cp;
2951 nfsattrbit_t attrbits, dattrbits;
2952 size_t tresid;
2953 u_int32_t *tl2 = NULL, fakefileno = 0xffffffff, rderr;
2954
2955 KASSERT(uiop->uio_iovcnt == 1 &&
2956 (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0,
2957 ("nfs readdirplusrpc bad uio"));
2958 *attrflagp = 0;
2959 if (eofp != NULL)
2960 *eofp = 0;
2961 ndp->ni_dvp = vp;
2962 nd->nd_mrep = NULL;
2963 cookie.lval[0] = cookiep->nfsuquad[0];
2964 cookie.lval[1] = cookiep->nfsuquad[1];
2965 tresid = uio_uio_resid(uiop);
2966
2967 /*
2968 * For NFSv4, first create the "." and ".." entries.
2969 */
2970 if (NFSHASNFSV4(nmp)) {
2971 NFSGETATTR_ATTRBIT(&dattrbits);
2972 NFSZERO_ATTRBIT(&attrbits);
2973 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID);
2974 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
2975 NFSATTRBIT_MOUNTEDONFILEID)) {
2976 NFSSETBIT_ATTRBIT(&attrbits,
2977 NFSATTRBIT_MOUNTEDONFILEID);
2978 gotmnton = 1;
2979 } else {
2980 /*
2981 * Must fake it. Use the fileno, except when the
2982 * fsid is != to that of the directory. For that
2983 * case, generate a fake fileno that is not the same.
2984 */
2985 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID);
2986 gotmnton = 0;
2987 }
2988
2989 /*
2990 * Joy, oh joy. For V4 we get to hand craft '.' and '..'.
2991 */
2992 if (uiop->uio_offset == 0) {
2993#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000
2994 error = VOP_GETATTR(vp, &nfsva.na_vattr, cred);
2995#else
2996 error = VOP_GETATTR(vp, &nfsva.na_vattr, cred, p);
2997#endif
2998 if (error)
2999 return (error);
3000 dotfileid = nfsva.na_fileid;
3001 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp);
3002 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3003 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
3004 *tl = txdr_unsigned(NFSV4OP_GETATTR);
3005 (void) nfsrv_putattrbit(nd, &attrbits);
3006 error = nfscl_request(nd, vp, p, cred, stuff);
3007 if (error)
3008 return (error);
3009 if (nd->nd_repstat == 0) {
3010 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3011 len = fxdr_unsigned(int, *(tl + 2));
3012 if (len > 0 && len <= NFSX_V4FHMAX)
3013 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
3014 else
3015 error = EPERM;
3016 if (!error) {
3017 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
3018 nfsva.na_mntonfileno = 0xffffffff;
3019 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
3020 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
3021 NULL, NULL, NULL, p, cred);
3022 if (error) {
3023 dotdotfileid = dotfileid;
3024 } else if (gotmnton) {
3025 if (nfsva.na_mntonfileno != 0xffffffff)
3026 dotdotfileid = nfsva.na_mntonfileno;
3027 else
3028 dotdotfileid = nfsva.na_fileid;
3029 } else if (nfsva.na_filesid[0] ==
3030 dnp->n_vattr.na_filesid[0] &&
3031 nfsva.na_filesid[1] ==
3032 dnp->n_vattr.na_filesid[1]) {
3033 dotdotfileid = nfsva.na_fileid;
3034 } else {
3035 do {
3036 fakefileno--;
3037 } while (fakefileno ==
3038 nfsva.na_fileid);
3039 dotdotfileid = fakefileno;
3040 }
3041 }
3042 } else if (nd->nd_repstat == NFSERR_NOENT) {
3043 /*
3044 * Lookupp returns NFSERR_NOENT when we are
3045 * at the root, so just use the current dir.
3046 */
3047 nd->nd_repstat = 0;
3048 dotdotfileid = dotfileid;
3049 } else {
3050 error = nd->nd_repstat;
3051 }
3052 mbuf_freem(nd->nd_mrep);
3053 if (error)
3054 return (error);
3055 nd->nd_mrep = NULL;
3056 dp = (struct dirent *)uio_iov_base(uiop);
3057 dp->d_type = DT_DIR;
3058 dp->d_fileno = dotfileid;
3059 dp->d_namlen = 1;
3060 dp->d_name[0] = '.';
3061 dp->d_name[1] = '\0';
3062 dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
3063 /*
3064 * Just make these offset cookie 0.
3065 */
3066 tl = (u_int32_t *)&dp->d_name[4];
3067 *tl++ = 0;
3068 *tl = 0;
3069 blksiz += dp->d_reclen;
3070 uio_uio_resid_add(uiop, -(dp->d_reclen));
3071 uiop->uio_offset += dp->d_reclen;
3072 uio_iov_base_add(uiop, dp->d_reclen);
3073 uio_iov_len_add(uiop, -(dp->d_reclen));
3074 dp = (struct dirent *)uio_iov_base(uiop);
3075 dp->d_type = DT_DIR;
3076 dp->d_fileno = dotdotfileid;
3077 dp->d_namlen = 2;
3078 dp->d_name[0] = '.';
3079 dp->d_name[1] = '.';
3080 dp->d_name[2] = '\0';
3081 dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
3082 /*
3083 * Just make these offset cookie 0.
3084 */
3085 tl = (u_int32_t *)&dp->d_name[4];
3086 *tl++ = 0;
3087 *tl = 0;
3088 blksiz += dp->d_reclen;
3089 uio_uio_resid_add(uiop, -(dp->d_reclen));
3090 uiop->uio_offset += dp->d_reclen;
3091 uio_iov_base_add(uiop, dp->d_reclen);
3092 uio_iov_len_add(uiop, -(dp->d_reclen));
3093 }
3094 NFSREADDIRPLUS_ATTRBIT(&attrbits);
3095 if (gotmnton)
3096 NFSSETBIT_ATTRBIT(&attrbits,
3097 NFSATTRBIT_MOUNTEDONFILEID);
3098 }
3099
3100 /*
3101 * Loop around doing readdir rpc's of size nm_readdirsize.
3102 * The stopping criteria is EOF or buffer full.
3103 */
3104 while (more_dirs && bigenough) {
3105 *attrflagp = 0;
3106 NFSCL_REQSTART(nd, NFSPROC_READDIRPLUS, vp);
3107 NFSM_BUILD(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
3108 *tl++ = cookie.lval[0];
3109 *tl++ = cookie.lval[1];
3110 if (cookie.qval == 0) {
3111 *tl++ = 0;
3112 *tl++ = 0;
3113 } else {
3114 NFSLOCKNODE(dnp);
3115 *tl++ = dnp->n_cookieverf.nfsuquad[0];
3116 *tl++ = dnp->n_cookieverf.nfsuquad[1];
3117 NFSUNLOCKNODE(dnp);
3118 }
3119 *tl++ = txdr_unsigned(nmp->nm_readdirsize);
3120 *tl = txdr_unsigned(nmp->nm_readdirsize);
3121 if (nd->nd_flag & ND_NFSV4) {
3122 (void) nfsrv_putattrbit(nd, &attrbits);
3123 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3124 *tl = txdr_unsigned(NFSV4OP_GETATTR);
3125 (void) nfsrv_putattrbit(nd, &dattrbits);
3126 }
3127 error = nfscl_request(nd, vp, p, cred, stuff);
3128 if (error)
3129 return (error);
3130 if (nd->nd_flag & ND_NFSV3)
3131 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3132 if (nd->nd_repstat || error) {
3133 if (!error)
3134 error = nd->nd_repstat;
3135 goto nfsmout;
3136 }
3137 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3138 NFSLOCKNODE(dnp);
3139 dnp->n_cookieverf.nfsuquad[0] = *tl++;
3140 dnp->n_cookieverf.nfsuquad[1] = *tl++;
3141 NFSUNLOCKNODE(dnp);
3142 more_dirs = fxdr_unsigned(int, *tl);
3143 if (!more_dirs)
3144 tryformoredirs = 0;
3145
3146 /* loop thru the dir entries, doctoring them to 4bsd form */
3147 while (more_dirs && bigenough) {
3148 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3149 if (nd->nd_flag & ND_NFSV4) {
3150 ncookie.lval[0] = *tl++;
3151 ncookie.lval[1] = *tl++;
3152 } else {
3153 fileno = fxdr_unsigned(long, *++tl);
3154 tl++;
3155 }
3156 len = fxdr_unsigned(int, *tl);
3157 if (len <= 0 || len > NFS_MAXNAMLEN) {
3158 error = EBADRPC;
3159 goto nfsmout;
3160 }
3161 tlen = NFSM_RNDUP(len);
3162 if (tlen == len)
3163 tlen += 4; /* To ensure null termination */
3164 left = DIRBLKSIZ - blksiz;
3165 if ((tlen + DIRHDSIZ + NFSX_HYPER) > left) {
3166 dp->d_reclen += left;
3167 uio_iov_base_add(uiop, left);
3168 uio_iov_len_add(uiop, -(left));
3169 uio_uio_resid_add(uiop, -(left));
3170 uiop->uio_offset += left;
3171 blksiz = 0;
3172 }
3173 if ((tlen + DIRHDSIZ + NFSX_HYPER) > uio_uio_resid(uiop))
3174 bigenough = 0;
3175 if (bigenough) {
3176 dp = (struct dirent *)uio_iov_base(uiop);
3177 dp->d_namlen = len;
3178 dp->d_reclen = tlen + DIRHDSIZ + NFSX_HYPER;
3179 dp->d_type = DT_UNKNOWN;
3180 blksiz += dp->d_reclen;
3181 if (blksiz == DIRBLKSIZ)
3182 blksiz = 0;
3183 uio_uio_resid_add(uiop, -(DIRHDSIZ));
3184 uiop->uio_offset += DIRHDSIZ;
3185 uio_iov_base_add(uiop, DIRHDSIZ);
3186 uio_iov_len_add(uiop, -(DIRHDSIZ));
3187 cnp->cn_nameptr = uio_iov_base(uiop);
3188 cnp->cn_namelen = len;
3189 NFSCNHASHZERO(cnp);
3190 error = nfsm_mbufuio(nd, uiop, len);
3191 if (error)
3192 goto nfsmout;
3193 cp = uio_iov_base(uiop);
3194 tlen -= len;
3195 *cp = '\0';
3196 cp += tlen; /* points to cookie storage */
3197 tl2 = (u_int32_t *)cp;
3198 if (len == 2 && cnp->cn_nameptr[0] == '.' &&
3199 cnp->cn_nameptr[1] == '.')
3200 isdotdot = 1;
3201 else
3202 isdotdot = 0;
3203 uio_iov_base_add(uiop, (tlen + NFSX_HYPER));
3204 uio_iov_len_add(uiop, -(tlen + NFSX_HYPER));
3205 uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER));
3206 uiop->uio_offset += (tlen + NFSX_HYPER);
3207 } else {
3208 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
3209 if (error)
3210 goto nfsmout;
3211 }
3212 nfhp = NULL;
3213 if (nd->nd_flag & ND_NFSV3) {
3214 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3215 ncookie.lval[0] = *tl++;
3216 ncookie.lval[1] = *tl++;
3217 attrflag = fxdr_unsigned(int, *tl);
3218 if (attrflag) {
3219 error = nfsm_loadattr(nd, &nfsva);
3220 if (error)
3221 goto nfsmout;
3222 }
3223 NFSM_DISSECT(tl,u_int32_t *,NFSX_UNSIGNED);
3224 if (*tl) {
3225 error = nfsm_getfh(nd, &nfhp);
3226 if (error)
3227 goto nfsmout;
3228 }
3229 if (!attrflag && nfhp != NULL) {
3230 FREE((caddr_t)nfhp, M_NFSFH);
3231 nfhp = NULL;
3232 }
3233 } else {
3234 rderr = 0;
3235 nfsva.na_mntonfileno = 0xffffffff;
3236 error = nfsv4_loadattr(nd, NULL, &nfsva, &nfhp,
3237 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
3238 NULL, NULL, &rderr, p, cred);
3239 if (error)
3240 goto nfsmout;
3241 }
3242
3243 if (bigenough) {
3244 if (nd->nd_flag & ND_NFSV4) {
3245 if (rderr) {
3246 dp->d_fileno = 0;
3247 } else if (gotmnton) {
3248 if (nfsva.na_mntonfileno != 0xffffffff)
3249 dp->d_fileno = nfsva.na_mntonfileno;
3250 else
3251 dp->d_fileno = nfsva.na_fileid;
3252 } else if (nfsva.na_filesid[0] ==
3253 dnp->n_vattr.na_filesid[0] &&
3254 nfsva.na_filesid[1] ==
3255 dnp->n_vattr.na_filesid[1]) {
3256 dp->d_fileno = nfsva.na_fileid;
3257 } else {
3258 do {
3259 fakefileno--;
3260 } while (fakefileno ==
3261 nfsva.na_fileid);
3262 dp->d_fileno = fakefileno;
3263 }
3264 } else {
3265 dp->d_fileno = fileno;
3266 }
3267 *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] =
3268 ncookie.lval[0];
3269 *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] =
3270 ncookie.lval[1];
3271
3272 if (nfhp != NULL) {
3273 if (NFSRV_CMPFH(nfhp->nfh_fh, nfhp->nfh_len,
3274 dnp->n_fhp->nfh_fh, dnp->n_fhp->nfh_len)) {
3275 VREF(vp);
3276 newvp = vp;
3277 unlocknewvp = 0;
3278 FREE((caddr_t)nfhp, M_NFSFH);
3279 np = dnp;
3280 } else if (isdotdot != 0) {
3281 /*
3282 * Skip doing a nfscl_nget() call for "..".
3283 * There's a race between acquiring the nfs
3284 * node here and lookups that look for the
3285 * directory being read (in the parent).
3286 * It would try to get a lock on ".." here,
3287 * owning the lock on the directory being
3288 * read. Lookup will hold the lock on ".."
3289 * and try to acquire the lock on the
3290 * directory being read.
3291 * If the directory is unlocked/relocked,
3292 * then there is a LOR with the buflock
3293 * vp is relocked.
3294 */
3295 free(nfhp, M_NFSFH);
3296 } else {
3297 error = nfscl_nget(vnode_mount(vp), vp,
3298 nfhp, cnp, p, &np, NULL, LK_EXCLUSIVE);
3299 if (!error) {
3300 newvp = NFSTOV(np);
3301 unlocknewvp = 1;
3302 }
3303 }
3304 nfhp = NULL;
3305 if (newvp != NULLVP) {
3306 error = nfscl_loadattrcache(&newvp,
3307 &nfsva, NULL, NULL, 0, 0);
3308 if (error) {
3309 if (unlocknewvp)
3310 vput(newvp);
3311 else
3312 vrele(newvp);
3313 goto nfsmout;
3314 }
3315 dp->d_type =
3316 vtonfs_dtype(np->n_vattr.na_type);
3317 ndp->ni_vp = newvp;
3318 NFSCNHASH(cnp, HASHINIT);
3319 if (cnp->cn_namelen <= NCHNAMLEN) {
3320 np->n_ctime = np->n_vattr.na_ctime;
3321 cache_enter(ndp->ni_dvp,ndp->ni_vp,cnp);
3320 cache_enter_time(ndp->ni_dvp,
3321 ndp->ni_vp, cnp,
3322 &nfsva.na_ctime);
3322 }
3323 if (unlocknewvp)
3324 vput(newvp);
3325 else
3326 vrele(newvp);
3327 newvp = NULLVP;
3328 }
3329 }
3330 } else if (nfhp != NULL) {
3331 FREE((caddr_t)nfhp, M_NFSFH);
3332 }
3333 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3334 more_dirs = fxdr_unsigned(int, *tl);
3335 }
3336 /*
3337 * If at end of rpc data, get the eof boolean
3338 */
3339 if (!more_dirs) {
3340 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3341 eof = fxdr_unsigned(int, *tl);
3342 if (tryformoredirs)
3343 more_dirs = !eof;
3344 if (nd->nd_flag & ND_NFSV4) {
3345 error = nfscl_postop_attr(nd, nap, attrflagp,
3346 stuff);
3347 if (error)
3348 goto nfsmout;
3349 }
3350 }
3351 mbuf_freem(nd->nd_mrep);
3352 nd->nd_mrep = NULL;
3353 }
3354 /*
3355 * Fill last record, iff any, out to a multiple of DIRBLKSIZ
3356 * by increasing d_reclen for the last record.
3357 */
3358 if (blksiz > 0) {
3359 left = DIRBLKSIZ - blksiz;
3360 dp->d_reclen += left;
3361 uio_iov_base_add(uiop, left);
3362 uio_iov_len_add(uiop, -(left));
3363 uio_uio_resid_add(uiop, -(left));
3364 uiop->uio_offset += left;
3365 }
3366
3367 /*
3368 * If returning no data, assume end of file.
3369 * If not bigenough, return not end of file, since you aren't
3370 * returning all the data
3371 * Otherwise, return the eof flag from the server.
3372 */
3373 if (eofp != NULL) {
3374 if (tresid == uio_uio_resid(uiop))
3375 *eofp = 1;
3376 else if (!bigenough)
3377 *eofp = 0;
3378 else
3379 *eofp = eof;
3380 }
3381
3382 /*
3383 * Add extra empty records to any remaining DIRBLKSIZ chunks.
3384 */
3385 while (uio_uio_resid(uiop) > 0 && uio_uio_resid(uiop) != tresid) {
3386 dp = (struct dirent *)uio_iov_base(uiop);
3387 dp->d_type = DT_UNKNOWN;
3388 dp->d_fileno = 0;
3389 dp->d_namlen = 0;
3390 dp->d_name[0] = '\0';
3391 tl = (u_int32_t *)&dp->d_name[4];
3392 *tl++ = cookie.lval[0];
3393 *tl = cookie.lval[1];
3394 dp->d_reclen = DIRBLKSIZ;
3395 uio_iov_base_add(uiop, DIRBLKSIZ);
3396 uio_iov_len_add(uiop, -(DIRBLKSIZ));
3397 uio_uio_resid_add(uiop, -(DIRBLKSIZ));
3398 uiop->uio_offset += DIRBLKSIZ;
3399 }
3400
3401nfsmout:
3402 if (nd->nd_mrep != NULL)
3403 mbuf_freem(nd->nd_mrep);
3404 return (error);
3405}
3406#endif /* !APPLE */
3407
3408/*
3409 * Nfs commit rpc
3410 */
3411APPLESTATIC int
3412nfsrpc_commit(vnode_t vp, u_quad_t offset, int cnt, struct ucred *cred,
3413 NFSPROC_T *p, u_char *verfp, struct nfsvattr *nap, int *attrflagp,
3414 void *stuff)
3415{
3416 u_int32_t *tl;
3417 struct nfsrv_descript nfsd, *nd = &nfsd;
3418 nfsattrbit_t attrbits;
3419 int error;
3420
3421 *attrflagp = 0;
3422 NFSCL_REQSTART(nd, NFSPROC_COMMIT, vp);
3423 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3424 txdr_hyper(offset, tl);
3425 tl += 2;
3426 *tl = txdr_unsigned(cnt);
3427 if (nd->nd_flag & ND_NFSV4) {
3428 /*
3429 * And do a Getattr op.
3430 */
3431 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3432 *tl = txdr_unsigned(NFSV4OP_GETATTR);
3433 NFSGETATTR_ATTRBIT(&attrbits);
3434 (void) nfsrv_putattrbit(nd, &attrbits);
3435 }
3436 error = nfscl_request(nd, vp, p, cred, stuff);
3437 if (error)
3438 return (error);
3439 error = nfscl_wcc_data(nd, vp, nap, attrflagp, NULL, stuff);
3440 if (!error && !nd->nd_repstat) {
3441 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
3442 NFSBCOPY((caddr_t)tl, verfp, NFSX_VERF);
3443 if (nd->nd_flag & ND_NFSV4)
3444 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3445 }
3446nfsmout:
3447 if (!error && nd->nd_repstat)
3448 error = nd->nd_repstat;
3449 mbuf_freem(nd->nd_mrep);
3450 return (error);
3451}
3452
3453/*
3454 * NFS byte range lock rpc.
3455 * (Mostly just calls one of the three lower level RPC routines.)
3456 */
3457APPLESTATIC int
3458nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
3459 int reclaim, struct ucred *cred, NFSPROC_T *p, void *id, int flags)
3460{
3461 struct nfscllockowner *lp;
3462 struct nfsclclient *clp;
3463 struct nfsfh *nfhp;
3464 struct nfsrv_descript nfsd, *nd = &nfsd;
3465 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
3466 u_int64_t off, len;
3467 off_t start, end;
3468 u_int32_t clidrev = 0;
3469 int error = 0, newone = 0, expireret = 0, retrycnt, donelocally;
3470 int callcnt, dorpc;
3471
3472 /*
3473 * Convert the flock structure into a start and end and do POSIX
3474 * bounds checking.
3475 */
3476 switch (fl->l_whence) {
3477 case SEEK_SET:
3478 case SEEK_CUR:
3479 /*
3480 * Caller is responsible for adding any necessary offset
3481 * when SEEK_CUR is used.
3482 */
3483 start = fl->l_start;
3484 off = fl->l_start;
3485 break;
3486 case SEEK_END:
3487 start = size + fl->l_start;
3488 off = size + fl->l_start;
3489 break;
3490 default:
3491 return (EINVAL);
3492 };
3493 if (start < 0)
3494 return (EINVAL);
3495 if (fl->l_len != 0) {
3496 end = start + fl->l_len - 1;
3497 if (end < start)
3498 return (EINVAL);
3499 }
3500
3501 len = fl->l_len;
3502 if (len == 0)
3503 len = NFS64BITSSET;
3504 retrycnt = 0;
3505 do {
3506 nd->nd_repstat = 0;
3507 if (op == F_GETLK) {
3508 error = nfscl_getcl(vp, cred, p, &clp);
3509 if (error)
3510 return (error);
3511 error = nfscl_lockt(vp, clp, off, len, fl, p, id, flags);
3512 if (!error) {
3513 clidrev = clp->nfsc_clientidrev;
3514 error = nfsrpc_lockt(nd, vp, clp, off, len, fl, cred,
3515 p, id, flags);
3516 } else if (error == -1) {
3517 error = 0;
3518 }
3519 nfscl_clientrelease(clp);
3520 } else if (op == F_UNLCK && fl->l_type == F_UNLCK) {
3521 /*
3522 * We must loop around for all lockowner cases.
3523 */
3524 callcnt = 0;
3525 error = nfscl_getcl(vp, cred, p, &clp);
3526 if (error)
3527 return (error);
3528 do {
3529 error = nfscl_relbytelock(vp, off, len, cred, p, callcnt,
3530 clp, id, flags, &lp, &dorpc);
3531 /*
3532 * If it returns a NULL lp, we're done.
3533 */
3534 if (lp == NULL) {
3535 if (callcnt == 0)
3536 nfscl_clientrelease(clp);
3537 else
3538 nfscl_releasealllocks(clp, vp, p, id, flags);
3539 return (error);
3540 }
3541 if (nmp->nm_clp != NULL)
3542 clidrev = nmp->nm_clp->nfsc_clientidrev;
3543 else
3544 clidrev = 0;
3545 /*
3546 * If the server doesn't support Posix lock semantics,
3547 * only allow locks on the entire file, since it won't
3548 * handle overlapping byte ranges.
3549 * There might still be a problem when a lock
3550 * upgrade/downgrade (read<->write) occurs, since the
3551 * server "might" expect an unlock first?
3552 */
3553 if (dorpc && (lp->nfsl_open->nfso_posixlock ||
3554 (off == 0 && len == NFS64BITSSET))) {
3555 /*
3556 * Since the lock records will go away, we must
3557 * wait for grace and delay here.
3558 */
3559 do {
3560 error = nfsrpc_locku(nd, nmp, lp, off, len,
3561 NFSV4LOCKT_READ, cred, p, 0);
3562 if ((nd->nd_repstat == NFSERR_GRACE ||
3563 nd->nd_repstat == NFSERR_DELAY) &&
3564 error == 0)
3565 (void) nfs_catnap(PZERO, (int)nd->nd_repstat,
3566 "nfs_advlock");
3567 } while ((nd->nd_repstat == NFSERR_GRACE ||
3568 nd->nd_repstat == NFSERR_DELAY) && error == 0);
3569 }
3570 callcnt++;
3571 } while (error == 0 && nd->nd_repstat == 0);
3572 nfscl_releasealllocks(clp, vp, p, id, flags);
3573 } else if (op == F_SETLK) {
3574 error = nfscl_getbytelock(vp, off, len, fl->l_type, cred, p,
3575 NULL, 0, id, flags, NULL, NULL, &lp, &newone, &donelocally);
3576 if (error || donelocally) {
3577 return (error);
3578 }
3579 if (nmp->nm_clp != NULL)
3580 clidrev = nmp->nm_clp->nfsc_clientidrev;
3581 else
3582 clidrev = 0;
3583 nfhp = VTONFS(vp)->n_fhp;
3584 if (!lp->nfsl_open->nfso_posixlock &&
3585 (off != 0 || len != NFS64BITSSET)) {
3586 error = EINVAL;
3587 } else {
3588 error = nfsrpc_lock(nd, nmp, vp, nfhp->nfh_fh,
3589 nfhp->nfh_len, lp, newone, reclaim, off,
3590 len, fl->l_type, cred, p, 0);
3591 }
3592 if (!error)
3593 error = nd->nd_repstat;
3594 nfscl_lockrelease(lp, error, newone);
3595 } else {
3596 error = EINVAL;
3597 }
3598 if (!error)
3599 error = nd->nd_repstat;
3600 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
3601 error == NFSERR_STALEDONTRECOVER ||
3602 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY) {
3603 (void) nfs_catnap(PZERO, error, "nfs_advlock");
3604 } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID)
3605 && clidrev != 0) {
3606 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
3607 retrycnt++;
3608 }
3609 } while (error == NFSERR_GRACE ||
3610 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY ||
3611 error == NFSERR_STALEDONTRECOVER || error == NFSERR_STALESTATEID ||
3612 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
3613 expireret == 0 && clidrev != 0 && retrycnt < 4));
3614 if (error && retrycnt >= 4)
3615 error = EIO;
3616 return (error);
3617}
3618
3619/*
3620 * The lower level routine for the LockT case.
3621 */
3622APPLESTATIC int
3623nfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp,
3624 struct nfsclclient *clp, u_int64_t off, u_int64_t len, struct flock *fl,
3625 struct ucred *cred, NFSPROC_T *p, void *id, int flags)
3626{
3627 u_int32_t *tl;
3628 int error, type, size;
3629 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
3630 struct nfsnode *np;
3631
3632 NFSCL_REQSTART(nd, NFSPROC_LOCKT, vp);
3633 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
3634 if (fl->l_type == F_RDLCK)
3635 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
3636 else
3637 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
3638 txdr_hyper(off, tl);
3639 tl += 2;
3640 txdr_hyper(len, tl);
3641 tl += 2;
3642 *tl++ = clp->nfsc_clientid.lval[0];
3643 *tl = clp->nfsc_clientid.lval[1];
3644 nfscl_filllockowner(id, own, flags);
3645 np = VTONFS(vp);
3646 NFSBCOPY(np->n_fhp->nfh_fh, &own[NFSV4CL_LOCKNAMELEN],
3647 np->n_fhp->nfh_len);
3648 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + np->n_fhp->nfh_len);
3649 error = nfscl_request(nd, vp, p, cred, NULL);
3650 if (error)
3651 return (error);
3652 if (nd->nd_repstat == 0) {
3653 fl->l_type = F_UNLCK;
3654 } else if (nd->nd_repstat == NFSERR_DENIED) {
3655 nd->nd_repstat = 0;
3656 fl->l_whence = SEEK_SET;
3657 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
3658 fl->l_start = fxdr_hyper(tl);
3659 tl += 2;
3660 len = fxdr_hyper(tl);
3661 tl += 2;
3662 if (len == NFS64BITSSET)
3663 fl->l_len = 0;
3664 else
3665 fl->l_len = len;
3666 type = fxdr_unsigned(int, *tl++);
3667 if (type == NFSV4LOCKT_WRITE)
3668 fl->l_type = F_WRLCK;
3669 else
3670 fl->l_type = F_RDLCK;
3671 /*
3672 * XXX For now, I have no idea what to do with the
3673 * conflicting lock_owner, so I'll just set the pid == 0
3674 * and skip over the lock_owner.
3675 */
3676 fl->l_pid = (pid_t)0;
3677 tl += 2;
3678 size = fxdr_unsigned(int, *tl);
3679 if (size < 0 || size > NFSV4_OPAQUELIMIT)
3680 error = EBADRPC;
3681 if (!error)
3682 error = nfsm_advance(nd, NFSM_RNDUP(size), -1);
3683 } else if (nd->nd_repstat == NFSERR_STALECLIENTID)
3684 nfscl_initiate_recovery(clp);
3685nfsmout:
3686 mbuf_freem(nd->nd_mrep);
3687 return (error);
3688}
3689
3690/*
3691 * Lower level function that performs the LockU RPC.
3692 */
3693static int
3694nfsrpc_locku(struct nfsrv_descript *nd, struct nfsmount *nmp,
3695 struct nfscllockowner *lp, u_int64_t off, u_int64_t len,
3696 u_int32_t type, struct ucred *cred, NFSPROC_T *p, int syscred)
3697{
3698 u_int32_t *tl;
3699 int error;
3700
3701 nfscl_reqstart(nd, NFSPROC_LOCKU, nmp, lp->nfsl_open->nfso_fh,
3702 lp->nfsl_open->nfso_fhlen, NULL);
3703 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
3704 *tl++ = txdr_unsigned(type);
3705 *tl = txdr_unsigned(lp->nfsl_seqid);
3706 if (nfstest_outofseq &&
3707 (arc4random() % nfstest_outofseq) == 0)
3708 *tl = txdr_unsigned(lp->nfsl_seqid + 1);
3709 tl++;
3710 *tl++ = lp->nfsl_stateid.seqid;
3711 *tl++ = lp->nfsl_stateid.other[0];
3712 *tl++ = lp->nfsl_stateid.other[1];
3713 *tl++ = lp->nfsl_stateid.other[2];
3714 txdr_hyper(off, tl);
3715 tl += 2;
3716 txdr_hyper(len, tl);
3717 if (syscred)
3718 nd->nd_flag |= ND_USEGSSNAME;
3719 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
3720 NFS_PROG, NFS_VER4, NULL, 1, NULL);
3721 NFSCL_INCRSEQID(lp->nfsl_seqid, nd);
3722 if (error)
3723 return (error);
3724 if (nd->nd_repstat == 0) {
3725 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3726 lp->nfsl_stateid.seqid = *tl++;
3727 lp->nfsl_stateid.other[0] = *tl++;
3728 lp->nfsl_stateid.other[1] = *tl++;
3729 lp->nfsl_stateid.other[2] = *tl;
3730 } else if (nd->nd_repstat == NFSERR_STALESTATEID)
3731 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp);
3732nfsmout:
3733 mbuf_freem(nd->nd_mrep);
3734 return (error);
3735}
3736
3737/*
3738 * The actual Lock RPC.
3739 */
3740APPLESTATIC int
3741nfsrpc_lock(struct nfsrv_descript *nd, struct nfsmount *nmp, vnode_t vp,
3742 u_int8_t *nfhp, int fhlen, struct nfscllockowner *lp, int newone,
3743 int reclaim, u_int64_t off, u_int64_t len, short type, struct ucred *cred,
3744 NFSPROC_T *p, int syscred)
3745{
3746 u_int32_t *tl;
3747 int error, size;
3748 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
3749
3750 nfscl_reqstart(nd, NFSPROC_LOCK, nmp, nfhp, fhlen, NULL);
3751 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
3752 if (type == F_RDLCK)
3753 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
3754 else
3755 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
3756 *tl++ = txdr_unsigned(reclaim);
3757 txdr_hyper(off, tl);
3758 tl += 2;
3759 txdr_hyper(len, tl);
3760 tl += 2;
3761 if (newone) {
3762 *tl = newnfs_true;
3763 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID +
3764 2 * NFSX_UNSIGNED + NFSX_HYPER);
3765 *tl++ = txdr_unsigned(lp->nfsl_open->nfso_own->nfsow_seqid);
3766 *tl++ = lp->nfsl_open->nfso_stateid.seqid;
3767 *tl++ = lp->nfsl_open->nfso_stateid.other[0];
3768 *tl++ = lp->nfsl_open->nfso_stateid.other[1];
3769 *tl++ = lp->nfsl_open->nfso_stateid.other[2];
3770 *tl++ = txdr_unsigned(lp->nfsl_seqid);
3771 *tl++ = lp->nfsl_open->nfso_own->nfsow_clp->nfsc_clientid.lval[0];
3772 *tl = lp->nfsl_open->nfso_own->nfsow_clp->nfsc_clientid.lval[1];
3773 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN);
3774 NFSBCOPY(nfhp, &own[NFSV4CL_LOCKNAMELEN], fhlen);
3775 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen);
3776 } else {
3777 *tl = newnfs_false;
3778 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
3779 *tl++ = lp->nfsl_stateid.seqid;
3780 *tl++ = lp->nfsl_stateid.other[0];
3781 *tl++ = lp->nfsl_stateid.other[1];
3782 *tl++ = lp->nfsl_stateid.other[2];
3783 *tl = txdr_unsigned(lp->nfsl_seqid);
3784 if (nfstest_outofseq &&
3785 (arc4random() % nfstest_outofseq) == 0)
3786 *tl = txdr_unsigned(lp->nfsl_seqid + 1);
3787 }
3788 if (syscred)
3789 nd->nd_flag |= ND_USEGSSNAME;
3790 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
3791 NFS_PROG, NFS_VER4, NULL, 1, NULL);
3792 if (error)
3793 return (error);
3794 if (newone)
3795 NFSCL_INCRSEQID(lp->nfsl_open->nfso_own->nfsow_seqid, nd);
3796 NFSCL_INCRSEQID(lp->nfsl_seqid, nd);
3797 if (nd->nd_repstat == 0) {
3798 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3799 lp->nfsl_stateid.seqid = *tl++;
3800 lp->nfsl_stateid.other[0] = *tl++;
3801 lp->nfsl_stateid.other[1] = *tl++;
3802 lp->nfsl_stateid.other[2] = *tl;
3803 } else if (nd->nd_repstat == NFSERR_DENIED) {
3804 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
3805 size = fxdr_unsigned(int, *(tl + 7));
3806 if (size < 0 || size > NFSV4_OPAQUELIMIT)
3807 error = EBADRPC;
3808 if (!error)
3809 error = nfsm_advance(nd, NFSM_RNDUP(size), -1);
3810 } else if (nd->nd_repstat == NFSERR_STALESTATEID)
3811 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp);
3812nfsmout:
3813 mbuf_freem(nd->nd_mrep);
3814 return (error);
3815}
3816
3817/*
3818 * nfs statfs rpc
3819 * (always called with the vp for the mount point)
3820 */
3821APPLESTATIC int
3822nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp,
3823 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
3824 void *stuff)
3825{
3826 u_int32_t *tl = NULL;
3827 struct nfsrv_descript nfsd, *nd = &nfsd;
3828 struct nfsmount *nmp;
3829 nfsattrbit_t attrbits;
3830 int error;
3831
3832 *attrflagp = 0;
3833 nmp = VFSTONFS(vnode_mount(vp));
3834 if (NFSHASNFSV4(nmp)) {
3835 /*
3836 * For V4, you actually do a getattr.
3837 */
3838 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
3839 NFSSTATFS_GETATTRBIT(&attrbits);
3840 (void) nfsrv_putattrbit(nd, &attrbits);
3841 nd->nd_flag |= ND_USEGSSNAME;
3842 error = nfscl_request(nd, vp, p, cred, stuff);
3843 if (error)
3844 return (error);
3845 if (nd->nd_repstat == 0) {
3846 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
3847 NULL, NULL, sbp, fsp, NULL, 0, NULL, NULL, NULL, p,
3848 cred);
3849 if (!error) {
3850 nmp->nm_fsid[0] = nap->na_filesid[0];
3851 nmp->nm_fsid[1] = nap->na_filesid[1];
3852 NFSSETHASSETFSID(nmp);
3853 *attrflagp = 1;
3854 }
3855 } else {
3856 error = nd->nd_repstat;
3857 }
3858 if (error)
3859 goto nfsmout;
3860 } else {
3861 NFSCL_REQSTART(nd, NFSPROC_FSSTAT, vp);
3862 error = nfscl_request(nd, vp, p, cred, stuff);
3863 if (error)
3864 return (error);
3865 if (nd->nd_flag & ND_NFSV3) {
3866 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3867 if (error)
3868 goto nfsmout;
3869 }
3870 if (nd->nd_repstat) {
3871 error = nd->nd_repstat;
3872 goto nfsmout;
3873 }
3874 NFSM_DISSECT(tl, u_int32_t *,
3875 NFSX_STATFS(nd->nd_flag & ND_NFSV3));
3876 }
3877 if (NFSHASNFSV3(nmp)) {
3878 sbp->sf_tbytes = fxdr_hyper(tl); tl += 2;
3879 sbp->sf_fbytes = fxdr_hyper(tl); tl += 2;
3880 sbp->sf_abytes = fxdr_hyper(tl); tl += 2;
3881 sbp->sf_tfiles = fxdr_hyper(tl); tl += 2;
3882 sbp->sf_ffiles = fxdr_hyper(tl); tl += 2;
3883 sbp->sf_afiles = fxdr_hyper(tl); tl += 2;
3884 sbp->sf_invarsec = fxdr_unsigned(u_int32_t, *tl);
3885 } else if (NFSHASNFSV4(nmp) == 0) {
3886 sbp->sf_tsize = fxdr_unsigned(u_int32_t, *tl++);
3887 sbp->sf_bsize = fxdr_unsigned(u_int32_t, *tl++);
3888 sbp->sf_blocks = fxdr_unsigned(u_int32_t, *tl++);
3889 sbp->sf_bfree = fxdr_unsigned(u_int32_t, *tl++);
3890 sbp->sf_bavail = fxdr_unsigned(u_int32_t, *tl);
3891 }
3892nfsmout:
3893 mbuf_freem(nd->nd_mrep);
3894 return (error);
3895}
3896
3897/*
3898 * nfs pathconf rpc
3899 */
3900APPLESTATIC int
3901nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc,
3902 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
3903 void *stuff)
3904{
3905 struct nfsrv_descript nfsd, *nd = &nfsd;
3906 struct nfsmount *nmp;
3907 u_int32_t *tl;
3908 nfsattrbit_t attrbits;
3909 int error;
3910
3911 *attrflagp = 0;
3912 nmp = VFSTONFS(vnode_mount(vp));
3913 if (NFSHASNFSV4(nmp)) {
3914 /*
3915 * For V4, you actually do a getattr.
3916 */
3917 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
3918 NFSPATHCONF_GETATTRBIT(&attrbits);
3919 (void) nfsrv_putattrbit(nd, &attrbits);
3920 nd->nd_flag |= ND_USEGSSNAME;
3921 error = nfscl_request(nd, vp, p, cred, stuff);
3922 if (error)
3923 return (error);
3924 if (nd->nd_repstat == 0) {
3925 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
3926 pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, p,
3927 cred);
3928 if (!error)
3929 *attrflagp = 1;
3930 } else {
3931 error = nd->nd_repstat;
3932 }
3933 } else {
3934 NFSCL_REQSTART(nd, NFSPROC_PATHCONF, vp);
3935 error = nfscl_request(nd, vp, p, cred, stuff);
3936 if (error)
3937 return (error);
3938 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3939 if (nd->nd_repstat && !error)
3940 error = nd->nd_repstat;
3941 if (!error) {
3942 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3PATHCONF);
3943 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl++);
3944 pc->pc_namemax = fxdr_unsigned(u_int32_t, *tl++);
3945 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl++);
3946 pc->pc_chownrestricted =
3947 fxdr_unsigned(u_int32_t, *tl++);
3948 pc->pc_caseinsensitive =
3949 fxdr_unsigned(u_int32_t, *tl++);
3950 pc->pc_casepreserving = fxdr_unsigned(u_int32_t, *tl);
3951 }
3952 }
3953nfsmout:
3954 mbuf_freem(nd->nd_mrep);
3955 return (error);
3956}
3957
3958/*
3959 * nfs version 3 fsinfo rpc call
3960 */
3961APPLESTATIC int
3962nfsrpc_fsinfo(vnode_t vp, struct nfsfsinfo *fsp, struct ucred *cred,
3963 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
3964{
3965 u_int32_t *tl;
3966 struct nfsrv_descript nfsd, *nd = &nfsd;
3967 int error;
3968
3969 *attrflagp = 0;
3970 NFSCL_REQSTART(nd, NFSPROC_FSINFO, vp);
3971 error = nfscl_request(nd, vp, p, cred, stuff);
3972 if (error)
3973 return (error);
3974 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3975 if (nd->nd_repstat && !error)
3976 error = nd->nd_repstat;
3977 if (!error) {
3978 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3FSINFO);
3979 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *tl++);
3980 fsp->fs_rtpref = fxdr_unsigned(u_int32_t, *tl++);
3981 fsp->fs_rtmult = fxdr_unsigned(u_int32_t, *tl++);
3982 fsp->fs_wtmax = fxdr_unsigned(u_int32_t, *tl++);
3983 fsp->fs_wtpref = fxdr_unsigned(u_int32_t, *tl++);
3984 fsp->fs_wtmult = fxdr_unsigned(u_int32_t, *tl++);
3985 fsp->fs_dtpref = fxdr_unsigned(u_int32_t, *tl++);
3986 fsp->fs_maxfilesize = fxdr_hyper(tl);
3987 tl += 2;
3988 fxdr_nfsv3time(tl, &fsp->fs_timedelta);
3989 tl += 2;
3990 fsp->fs_properties = fxdr_unsigned(u_int32_t, *tl);
3991 }
3992nfsmout:
3993 mbuf_freem(nd->nd_mrep);
3994 return (error);
3995}
3996
3997/*
3998 * This function performs the Renew RPC.
3999 */
4000APPLESTATIC int
4001nfsrpc_renew(struct nfsclclient *clp, struct ucred *cred, NFSPROC_T *p)
4002{
4003 u_int32_t *tl;
4004 struct nfsrv_descript nfsd;
4005 struct nfsrv_descript *nd = &nfsd;
4006 struct nfsmount *nmp;
4007 int error;
4008
4009 nmp = clp->nfsc_nmp;
4010 if (nmp == NULL)
4011 return (0);
4012 nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL);
4013 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4014 *tl++ = clp->nfsc_clientid.lval[0];
4015 *tl = clp->nfsc_clientid.lval[1];
4016 nd->nd_flag |= ND_USEGSSNAME;
4017 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4018 NFS_PROG, NFS_VER4, NULL, 1, NULL);
4019 if (error)
4020 return (error);
4021 error = nd->nd_repstat;
4022 mbuf_freem(nd->nd_mrep);
4023 return (error);
4024}
4025
4026/*
4027 * This function performs the Releaselockowner RPC.
4028 */
4029APPLESTATIC int
4030nfsrpc_rellockown(struct nfsmount *nmp, struct nfscllockowner *lp,
4031 uint8_t *fh, int fhlen, struct ucred *cred, NFSPROC_T *p)
4032{
4033 struct nfsrv_descript nfsd, *nd = &nfsd;
4034 u_int32_t *tl;
4035 int error;
4036 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
4037
4038 nfscl_reqstart(nd, NFSPROC_RELEASELCKOWN, nmp, NULL, 0, NULL);
4039 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4040 *tl++ = nmp->nm_clp->nfsc_clientid.lval[0];
4041 *tl = nmp->nm_clp->nfsc_clientid.lval[1];
4042 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN);
4043 NFSBCOPY(fh, &own[NFSV4CL_LOCKNAMELEN], fhlen);
4044 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen);
4045 nd->nd_flag |= ND_USEGSSNAME;
4046 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4047 NFS_PROG, NFS_VER4, NULL, 1, NULL);
4048 if (error)
4049 return (error);
4050 error = nd->nd_repstat;
4051 mbuf_freem(nd->nd_mrep);
4052 return (error);
4053}
4054
4055/*
4056 * This function performs the Compound to get the mount pt FH.
4057 */
4058APPLESTATIC int
4059nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred,
4060 NFSPROC_T *p)
4061{
4062 u_int32_t *tl;
4063 struct nfsrv_descript nfsd;
4064 struct nfsrv_descript *nd = &nfsd;
4065 u_char *cp, *cp2;
4066 int error, cnt, len, setnil;
4067 u_int32_t *opcntp;
4068
4069 nfscl_reqstart(nd, NFSPROC_PUTROOTFH, nmp, NULL, 0, &opcntp);
4070 cp = dirpath;
4071 cnt = 0;
4072 do {
4073 setnil = 0;
4074 while (*cp == '/')
4075 cp++;
4076 cp2 = cp;
4077 while (*cp2 != '\0' && *cp2 != '/')
4078 cp2++;
4079 if (*cp2 == '/') {
4080 setnil = 1;
4081 *cp2 = '\0';
4082 }
4083 if (cp2 != cp) {
4084 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4085 *tl = txdr_unsigned(NFSV4OP_LOOKUP);
4086 nfsm_strtom(nd, cp, strlen(cp));
4087 cnt++;
4088 }
4089 if (setnil)
4090 *cp2++ = '/';
4091 cp = cp2;
4092 } while (*cp != '\0');
4093 *opcntp = txdr_unsigned(2 + cnt);
4094 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4095 *tl = txdr_unsigned(NFSV4OP_GETFH);
4096 nd->nd_flag |= ND_USEGSSNAME;
4097 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4098 NFS_PROG, NFS_VER4, NULL, 1, NULL);
4099 if (error)
4100 return (error);
4101 if (nd->nd_repstat == 0) {
4102 NFSM_DISSECT(tl, u_int32_t *, (3 + 2 * cnt) * NFSX_UNSIGNED);
4103 tl += (2 + 2 * cnt);
4104 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
4105 len > NFSX_FHMAX) {
4106 nd->nd_repstat = NFSERR_BADXDR;
4107 } else {
4108 nd->nd_repstat = nfsrv_mtostr(nd, nmp->nm_fh, len);
4109 if (nd->nd_repstat == 0)
4110 nmp->nm_fhsize = len;
4111 }
4112 }
4113 error = nd->nd_repstat;
4114nfsmout:
4115 mbuf_freem(nd->nd_mrep);
4116 return (error);
4117}
4118
4119/*
4120 * This function performs the Delegreturn RPC.
4121 */
4122APPLESTATIC int
4123nfsrpc_delegreturn(struct nfscldeleg *dp, struct ucred *cred,
4124 struct nfsmount *nmp, NFSPROC_T *p, int syscred)
4125{
4126 u_int32_t *tl;
4127 struct nfsrv_descript nfsd;
4128 struct nfsrv_descript *nd = &nfsd;
4129 int error;
4130
4131 nfscl_reqstart(nd, NFSPROC_DELEGRETURN, nmp, dp->nfsdl_fh,
4132 dp->nfsdl_fhlen, NULL);
4133 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
4134 *tl++ = dp->nfsdl_stateid.seqid;
4135 *tl++ = dp->nfsdl_stateid.other[0];
4136 *tl++ = dp->nfsdl_stateid.other[1];
4137 *tl = dp->nfsdl_stateid.other[2];
4138 if (syscred)
4139 nd->nd_flag |= ND_USEGSSNAME;
4140 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4141 NFS_PROG, NFS_VER4, NULL, 1, NULL);
4142 if (error)
4143 return (error);
4144 error = nd->nd_repstat;
4145 mbuf_freem(nd->nd_mrep);
4146 return (error);
4147}
4148
4149/*
4150 * nfs getacl call.
4151 */
4152APPLESTATIC int
4153nfsrpc_getacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
4154 struct acl *aclp, void *stuff)
4155{
4156 struct nfsrv_descript nfsd, *nd = &nfsd;
4157 int error;
4158 nfsattrbit_t attrbits;
4159 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
4160
4161 if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp))
4162 return (EOPNOTSUPP);
4163 NFSCL_REQSTART(nd, NFSPROC_GETACL, vp);
4164 NFSZERO_ATTRBIT(&attrbits);
4165 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
4166 (void) nfsrv_putattrbit(nd, &attrbits);
4167 error = nfscl_request(nd, vp, p, cred, stuff);
4168 if (error)
4169 return (error);
4170 if (!nd->nd_repstat)
4171 error = nfsv4_loadattr(nd, vp, NULL, NULL, NULL, 0, NULL,
4172 NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, p, cred);
4173 else
4174 error = nd->nd_repstat;
4175 mbuf_freem(nd->nd_mrep);
4176 return (error);
4177}
4178
4179/*
4180 * nfs setacl call.
4181 */
4182APPLESTATIC int
4183nfsrpc_setacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
4184 struct acl *aclp, void *stuff)
4185{
4186 int error;
4187 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
4188
4189 if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp))
4190 return (EOPNOTSUPP);
4191 error = nfsrpc_setattr(vp, NULL, aclp, cred, p, NULL, NULL, stuff);
4192 return (error);
4193}
4194
4195/*
4196 * nfs setacl call.
4197 */
4198static int
4199nfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
4200 struct acl *aclp, nfsv4stateid_t *stateidp, void *stuff)
4201{
4202 struct nfsrv_descript nfsd, *nd = &nfsd;
4203 int error;
4204 nfsattrbit_t attrbits;
4205 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
4206
4207 if (!NFSHASNFSV4(nmp))
4208 return (EOPNOTSUPP);
4209 NFSCL_REQSTART(nd, NFSPROC_SETACL, vp);
4210 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
4211 NFSZERO_ATTRBIT(&attrbits);
4212 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
4213 (void) nfsv4_fillattr(nd, vnode_mount(vp), vp, aclp, NULL, NULL, 0,
4214 &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0);
4215 error = nfscl_request(nd, vp, p, cred, stuff);
4216 if (error)
4217 return (error);
4218 /* Don't care about the pre/postop attributes */
4219 mbuf_freem(nd->nd_mrep);
4220 return (nd->nd_repstat);
4221}
3323 }
3324 if (unlocknewvp)
3325 vput(newvp);
3326 else
3327 vrele(newvp);
3328 newvp = NULLVP;
3329 }
3330 }
3331 } else if (nfhp != NULL) {
3332 FREE((caddr_t)nfhp, M_NFSFH);
3333 }
3334 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3335 more_dirs = fxdr_unsigned(int, *tl);
3336 }
3337 /*
3338 * If at end of rpc data, get the eof boolean
3339 */
3340 if (!more_dirs) {
3341 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3342 eof = fxdr_unsigned(int, *tl);
3343 if (tryformoredirs)
3344 more_dirs = !eof;
3345 if (nd->nd_flag & ND_NFSV4) {
3346 error = nfscl_postop_attr(nd, nap, attrflagp,
3347 stuff);
3348 if (error)
3349 goto nfsmout;
3350 }
3351 }
3352 mbuf_freem(nd->nd_mrep);
3353 nd->nd_mrep = NULL;
3354 }
3355 /*
3356 * Fill last record, iff any, out to a multiple of DIRBLKSIZ
3357 * by increasing d_reclen for the last record.
3358 */
3359 if (blksiz > 0) {
3360 left = DIRBLKSIZ - blksiz;
3361 dp->d_reclen += left;
3362 uio_iov_base_add(uiop, left);
3363 uio_iov_len_add(uiop, -(left));
3364 uio_uio_resid_add(uiop, -(left));
3365 uiop->uio_offset += left;
3366 }
3367
3368 /*
3369 * If returning no data, assume end of file.
3370 * If not bigenough, return not end of file, since you aren't
3371 * returning all the data
3372 * Otherwise, return the eof flag from the server.
3373 */
3374 if (eofp != NULL) {
3375 if (tresid == uio_uio_resid(uiop))
3376 *eofp = 1;
3377 else if (!bigenough)
3378 *eofp = 0;
3379 else
3380 *eofp = eof;
3381 }
3382
3383 /*
3384 * Add extra empty records to any remaining DIRBLKSIZ chunks.
3385 */
3386 while (uio_uio_resid(uiop) > 0 && uio_uio_resid(uiop) != tresid) {
3387 dp = (struct dirent *)uio_iov_base(uiop);
3388 dp->d_type = DT_UNKNOWN;
3389 dp->d_fileno = 0;
3390 dp->d_namlen = 0;
3391 dp->d_name[0] = '\0';
3392 tl = (u_int32_t *)&dp->d_name[4];
3393 *tl++ = cookie.lval[0];
3394 *tl = cookie.lval[1];
3395 dp->d_reclen = DIRBLKSIZ;
3396 uio_iov_base_add(uiop, DIRBLKSIZ);
3397 uio_iov_len_add(uiop, -(DIRBLKSIZ));
3398 uio_uio_resid_add(uiop, -(DIRBLKSIZ));
3399 uiop->uio_offset += DIRBLKSIZ;
3400 }
3401
3402nfsmout:
3403 if (nd->nd_mrep != NULL)
3404 mbuf_freem(nd->nd_mrep);
3405 return (error);
3406}
3407#endif /* !APPLE */
3408
3409/*
3410 * Nfs commit rpc
3411 */
3412APPLESTATIC int
3413nfsrpc_commit(vnode_t vp, u_quad_t offset, int cnt, struct ucred *cred,
3414 NFSPROC_T *p, u_char *verfp, struct nfsvattr *nap, int *attrflagp,
3415 void *stuff)
3416{
3417 u_int32_t *tl;
3418 struct nfsrv_descript nfsd, *nd = &nfsd;
3419 nfsattrbit_t attrbits;
3420 int error;
3421
3422 *attrflagp = 0;
3423 NFSCL_REQSTART(nd, NFSPROC_COMMIT, vp);
3424 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3425 txdr_hyper(offset, tl);
3426 tl += 2;
3427 *tl = txdr_unsigned(cnt);
3428 if (nd->nd_flag & ND_NFSV4) {
3429 /*
3430 * And do a Getattr op.
3431 */
3432 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3433 *tl = txdr_unsigned(NFSV4OP_GETATTR);
3434 NFSGETATTR_ATTRBIT(&attrbits);
3435 (void) nfsrv_putattrbit(nd, &attrbits);
3436 }
3437 error = nfscl_request(nd, vp, p, cred, stuff);
3438 if (error)
3439 return (error);
3440 error = nfscl_wcc_data(nd, vp, nap, attrflagp, NULL, stuff);
3441 if (!error && !nd->nd_repstat) {
3442 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
3443 NFSBCOPY((caddr_t)tl, verfp, NFSX_VERF);
3444 if (nd->nd_flag & ND_NFSV4)
3445 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3446 }
3447nfsmout:
3448 if (!error && nd->nd_repstat)
3449 error = nd->nd_repstat;
3450 mbuf_freem(nd->nd_mrep);
3451 return (error);
3452}
3453
3454/*
3455 * NFS byte range lock rpc.
3456 * (Mostly just calls one of the three lower level RPC routines.)
3457 */
3458APPLESTATIC int
3459nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
3460 int reclaim, struct ucred *cred, NFSPROC_T *p, void *id, int flags)
3461{
3462 struct nfscllockowner *lp;
3463 struct nfsclclient *clp;
3464 struct nfsfh *nfhp;
3465 struct nfsrv_descript nfsd, *nd = &nfsd;
3466 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
3467 u_int64_t off, len;
3468 off_t start, end;
3469 u_int32_t clidrev = 0;
3470 int error = 0, newone = 0, expireret = 0, retrycnt, donelocally;
3471 int callcnt, dorpc;
3472
3473 /*
3474 * Convert the flock structure into a start and end and do POSIX
3475 * bounds checking.
3476 */
3477 switch (fl->l_whence) {
3478 case SEEK_SET:
3479 case SEEK_CUR:
3480 /*
3481 * Caller is responsible for adding any necessary offset
3482 * when SEEK_CUR is used.
3483 */
3484 start = fl->l_start;
3485 off = fl->l_start;
3486 break;
3487 case SEEK_END:
3488 start = size + fl->l_start;
3489 off = size + fl->l_start;
3490 break;
3491 default:
3492 return (EINVAL);
3493 };
3494 if (start < 0)
3495 return (EINVAL);
3496 if (fl->l_len != 0) {
3497 end = start + fl->l_len - 1;
3498 if (end < start)
3499 return (EINVAL);
3500 }
3501
3502 len = fl->l_len;
3503 if (len == 0)
3504 len = NFS64BITSSET;
3505 retrycnt = 0;
3506 do {
3507 nd->nd_repstat = 0;
3508 if (op == F_GETLK) {
3509 error = nfscl_getcl(vp, cred, p, &clp);
3510 if (error)
3511 return (error);
3512 error = nfscl_lockt(vp, clp, off, len, fl, p, id, flags);
3513 if (!error) {
3514 clidrev = clp->nfsc_clientidrev;
3515 error = nfsrpc_lockt(nd, vp, clp, off, len, fl, cred,
3516 p, id, flags);
3517 } else if (error == -1) {
3518 error = 0;
3519 }
3520 nfscl_clientrelease(clp);
3521 } else if (op == F_UNLCK && fl->l_type == F_UNLCK) {
3522 /*
3523 * We must loop around for all lockowner cases.
3524 */
3525 callcnt = 0;
3526 error = nfscl_getcl(vp, cred, p, &clp);
3527 if (error)
3528 return (error);
3529 do {
3530 error = nfscl_relbytelock(vp, off, len, cred, p, callcnt,
3531 clp, id, flags, &lp, &dorpc);
3532 /*
3533 * If it returns a NULL lp, we're done.
3534 */
3535 if (lp == NULL) {
3536 if (callcnt == 0)
3537 nfscl_clientrelease(clp);
3538 else
3539 nfscl_releasealllocks(clp, vp, p, id, flags);
3540 return (error);
3541 }
3542 if (nmp->nm_clp != NULL)
3543 clidrev = nmp->nm_clp->nfsc_clientidrev;
3544 else
3545 clidrev = 0;
3546 /*
3547 * If the server doesn't support Posix lock semantics,
3548 * only allow locks on the entire file, since it won't
3549 * handle overlapping byte ranges.
3550 * There might still be a problem when a lock
3551 * upgrade/downgrade (read<->write) occurs, since the
3552 * server "might" expect an unlock first?
3553 */
3554 if (dorpc && (lp->nfsl_open->nfso_posixlock ||
3555 (off == 0 && len == NFS64BITSSET))) {
3556 /*
3557 * Since the lock records will go away, we must
3558 * wait for grace and delay here.
3559 */
3560 do {
3561 error = nfsrpc_locku(nd, nmp, lp, off, len,
3562 NFSV4LOCKT_READ, cred, p, 0);
3563 if ((nd->nd_repstat == NFSERR_GRACE ||
3564 nd->nd_repstat == NFSERR_DELAY) &&
3565 error == 0)
3566 (void) nfs_catnap(PZERO, (int)nd->nd_repstat,
3567 "nfs_advlock");
3568 } while ((nd->nd_repstat == NFSERR_GRACE ||
3569 nd->nd_repstat == NFSERR_DELAY) && error == 0);
3570 }
3571 callcnt++;
3572 } while (error == 0 && nd->nd_repstat == 0);
3573 nfscl_releasealllocks(clp, vp, p, id, flags);
3574 } else if (op == F_SETLK) {
3575 error = nfscl_getbytelock(vp, off, len, fl->l_type, cred, p,
3576 NULL, 0, id, flags, NULL, NULL, &lp, &newone, &donelocally);
3577 if (error || donelocally) {
3578 return (error);
3579 }
3580 if (nmp->nm_clp != NULL)
3581 clidrev = nmp->nm_clp->nfsc_clientidrev;
3582 else
3583 clidrev = 0;
3584 nfhp = VTONFS(vp)->n_fhp;
3585 if (!lp->nfsl_open->nfso_posixlock &&
3586 (off != 0 || len != NFS64BITSSET)) {
3587 error = EINVAL;
3588 } else {
3589 error = nfsrpc_lock(nd, nmp, vp, nfhp->nfh_fh,
3590 nfhp->nfh_len, lp, newone, reclaim, off,
3591 len, fl->l_type, cred, p, 0);
3592 }
3593 if (!error)
3594 error = nd->nd_repstat;
3595 nfscl_lockrelease(lp, error, newone);
3596 } else {
3597 error = EINVAL;
3598 }
3599 if (!error)
3600 error = nd->nd_repstat;
3601 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
3602 error == NFSERR_STALEDONTRECOVER ||
3603 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY) {
3604 (void) nfs_catnap(PZERO, error, "nfs_advlock");
3605 } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID)
3606 && clidrev != 0) {
3607 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
3608 retrycnt++;
3609 }
3610 } while (error == NFSERR_GRACE ||
3611 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY ||
3612 error == NFSERR_STALEDONTRECOVER || error == NFSERR_STALESTATEID ||
3613 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
3614 expireret == 0 && clidrev != 0 && retrycnt < 4));
3615 if (error && retrycnt >= 4)
3616 error = EIO;
3617 return (error);
3618}
3619
3620/*
3621 * The lower level routine for the LockT case.
3622 */
3623APPLESTATIC int
3624nfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp,
3625 struct nfsclclient *clp, u_int64_t off, u_int64_t len, struct flock *fl,
3626 struct ucred *cred, NFSPROC_T *p, void *id, int flags)
3627{
3628 u_int32_t *tl;
3629 int error, type, size;
3630 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
3631 struct nfsnode *np;
3632
3633 NFSCL_REQSTART(nd, NFSPROC_LOCKT, vp);
3634 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
3635 if (fl->l_type == F_RDLCK)
3636 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
3637 else
3638 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
3639 txdr_hyper(off, tl);
3640 tl += 2;
3641 txdr_hyper(len, tl);
3642 tl += 2;
3643 *tl++ = clp->nfsc_clientid.lval[0];
3644 *tl = clp->nfsc_clientid.lval[1];
3645 nfscl_filllockowner(id, own, flags);
3646 np = VTONFS(vp);
3647 NFSBCOPY(np->n_fhp->nfh_fh, &own[NFSV4CL_LOCKNAMELEN],
3648 np->n_fhp->nfh_len);
3649 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + np->n_fhp->nfh_len);
3650 error = nfscl_request(nd, vp, p, cred, NULL);
3651 if (error)
3652 return (error);
3653 if (nd->nd_repstat == 0) {
3654 fl->l_type = F_UNLCK;
3655 } else if (nd->nd_repstat == NFSERR_DENIED) {
3656 nd->nd_repstat = 0;
3657 fl->l_whence = SEEK_SET;
3658 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
3659 fl->l_start = fxdr_hyper(tl);
3660 tl += 2;
3661 len = fxdr_hyper(tl);
3662 tl += 2;
3663 if (len == NFS64BITSSET)
3664 fl->l_len = 0;
3665 else
3666 fl->l_len = len;
3667 type = fxdr_unsigned(int, *tl++);
3668 if (type == NFSV4LOCKT_WRITE)
3669 fl->l_type = F_WRLCK;
3670 else
3671 fl->l_type = F_RDLCK;
3672 /*
3673 * XXX For now, I have no idea what to do with the
3674 * conflicting lock_owner, so I'll just set the pid == 0
3675 * and skip over the lock_owner.
3676 */
3677 fl->l_pid = (pid_t)0;
3678 tl += 2;
3679 size = fxdr_unsigned(int, *tl);
3680 if (size < 0 || size > NFSV4_OPAQUELIMIT)
3681 error = EBADRPC;
3682 if (!error)
3683 error = nfsm_advance(nd, NFSM_RNDUP(size), -1);
3684 } else if (nd->nd_repstat == NFSERR_STALECLIENTID)
3685 nfscl_initiate_recovery(clp);
3686nfsmout:
3687 mbuf_freem(nd->nd_mrep);
3688 return (error);
3689}
3690
3691/*
3692 * Lower level function that performs the LockU RPC.
3693 */
3694static int
3695nfsrpc_locku(struct nfsrv_descript *nd, struct nfsmount *nmp,
3696 struct nfscllockowner *lp, u_int64_t off, u_int64_t len,
3697 u_int32_t type, struct ucred *cred, NFSPROC_T *p, int syscred)
3698{
3699 u_int32_t *tl;
3700 int error;
3701
3702 nfscl_reqstart(nd, NFSPROC_LOCKU, nmp, lp->nfsl_open->nfso_fh,
3703 lp->nfsl_open->nfso_fhlen, NULL);
3704 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
3705 *tl++ = txdr_unsigned(type);
3706 *tl = txdr_unsigned(lp->nfsl_seqid);
3707 if (nfstest_outofseq &&
3708 (arc4random() % nfstest_outofseq) == 0)
3709 *tl = txdr_unsigned(lp->nfsl_seqid + 1);
3710 tl++;
3711 *tl++ = lp->nfsl_stateid.seqid;
3712 *tl++ = lp->nfsl_stateid.other[0];
3713 *tl++ = lp->nfsl_stateid.other[1];
3714 *tl++ = lp->nfsl_stateid.other[2];
3715 txdr_hyper(off, tl);
3716 tl += 2;
3717 txdr_hyper(len, tl);
3718 if (syscred)
3719 nd->nd_flag |= ND_USEGSSNAME;
3720 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
3721 NFS_PROG, NFS_VER4, NULL, 1, NULL);
3722 NFSCL_INCRSEQID(lp->nfsl_seqid, nd);
3723 if (error)
3724 return (error);
3725 if (nd->nd_repstat == 0) {
3726 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3727 lp->nfsl_stateid.seqid = *tl++;
3728 lp->nfsl_stateid.other[0] = *tl++;
3729 lp->nfsl_stateid.other[1] = *tl++;
3730 lp->nfsl_stateid.other[2] = *tl;
3731 } else if (nd->nd_repstat == NFSERR_STALESTATEID)
3732 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp);
3733nfsmout:
3734 mbuf_freem(nd->nd_mrep);
3735 return (error);
3736}
3737
3738/*
3739 * The actual Lock RPC.
3740 */
3741APPLESTATIC int
3742nfsrpc_lock(struct nfsrv_descript *nd, struct nfsmount *nmp, vnode_t vp,
3743 u_int8_t *nfhp, int fhlen, struct nfscllockowner *lp, int newone,
3744 int reclaim, u_int64_t off, u_int64_t len, short type, struct ucred *cred,
3745 NFSPROC_T *p, int syscred)
3746{
3747 u_int32_t *tl;
3748 int error, size;
3749 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
3750
3751 nfscl_reqstart(nd, NFSPROC_LOCK, nmp, nfhp, fhlen, NULL);
3752 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
3753 if (type == F_RDLCK)
3754 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
3755 else
3756 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
3757 *tl++ = txdr_unsigned(reclaim);
3758 txdr_hyper(off, tl);
3759 tl += 2;
3760 txdr_hyper(len, tl);
3761 tl += 2;
3762 if (newone) {
3763 *tl = newnfs_true;
3764 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID +
3765 2 * NFSX_UNSIGNED + NFSX_HYPER);
3766 *tl++ = txdr_unsigned(lp->nfsl_open->nfso_own->nfsow_seqid);
3767 *tl++ = lp->nfsl_open->nfso_stateid.seqid;
3768 *tl++ = lp->nfsl_open->nfso_stateid.other[0];
3769 *tl++ = lp->nfsl_open->nfso_stateid.other[1];
3770 *tl++ = lp->nfsl_open->nfso_stateid.other[2];
3771 *tl++ = txdr_unsigned(lp->nfsl_seqid);
3772 *tl++ = lp->nfsl_open->nfso_own->nfsow_clp->nfsc_clientid.lval[0];
3773 *tl = lp->nfsl_open->nfso_own->nfsow_clp->nfsc_clientid.lval[1];
3774 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN);
3775 NFSBCOPY(nfhp, &own[NFSV4CL_LOCKNAMELEN], fhlen);
3776 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen);
3777 } else {
3778 *tl = newnfs_false;
3779 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
3780 *tl++ = lp->nfsl_stateid.seqid;
3781 *tl++ = lp->nfsl_stateid.other[0];
3782 *tl++ = lp->nfsl_stateid.other[1];
3783 *tl++ = lp->nfsl_stateid.other[2];
3784 *tl = txdr_unsigned(lp->nfsl_seqid);
3785 if (nfstest_outofseq &&
3786 (arc4random() % nfstest_outofseq) == 0)
3787 *tl = txdr_unsigned(lp->nfsl_seqid + 1);
3788 }
3789 if (syscred)
3790 nd->nd_flag |= ND_USEGSSNAME;
3791 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
3792 NFS_PROG, NFS_VER4, NULL, 1, NULL);
3793 if (error)
3794 return (error);
3795 if (newone)
3796 NFSCL_INCRSEQID(lp->nfsl_open->nfso_own->nfsow_seqid, nd);
3797 NFSCL_INCRSEQID(lp->nfsl_seqid, nd);
3798 if (nd->nd_repstat == 0) {
3799 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3800 lp->nfsl_stateid.seqid = *tl++;
3801 lp->nfsl_stateid.other[0] = *tl++;
3802 lp->nfsl_stateid.other[1] = *tl++;
3803 lp->nfsl_stateid.other[2] = *tl;
3804 } else if (nd->nd_repstat == NFSERR_DENIED) {
3805 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
3806 size = fxdr_unsigned(int, *(tl + 7));
3807 if (size < 0 || size > NFSV4_OPAQUELIMIT)
3808 error = EBADRPC;
3809 if (!error)
3810 error = nfsm_advance(nd, NFSM_RNDUP(size), -1);
3811 } else if (nd->nd_repstat == NFSERR_STALESTATEID)
3812 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp);
3813nfsmout:
3814 mbuf_freem(nd->nd_mrep);
3815 return (error);
3816}
3817
3818/*
3819 * nfs statfs rpc
3820 * (always called with the vp for the mount point)
3821 */
3822APPLESTATIC int
3823nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp,
3824 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
3825 void *stuff)
3826{
3827 u_int32_t *tl = NULL;
3828 struct nfsrv_descript nfsd, *nd = &nfsd;
3829 struct nfsmount *nmp;
3830 nfsattrbit_t attrbits;
3831 int error;
3832
3833 *attrflagp = 0;
3834 nmp = VFSTONFS(vnode_mount(vp));
3835 if (NFSHASNFSV4(nmp)) {
3836 /*
3837 * For V4, you actually do a getattr.
3838 */
3839 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
3840 NFSSTATFS_GETATTRBIT(&attrbits);
3841 (void) nfsrv_putattrbit(nd, &attrbits);
3842 nd->nd_flag |= ND_USEGSSNAME;
3843 error = nfscl_request(nd, vp, p, cred, stuff);
3844 if (error)
3845 return (error);
3846 if (nd->nd_repstat == 0) {
3847 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
3848 NULL, NULL, sbp, fsp, NULL, 0, NULL, NULL, NULL, p,
3849 cred);
3850 if (!error) {
3851 nmp->nm_fsid[0] = nap->na_filesid[0];
3852 nmp->nm_fsid[1] = nap->na_filesid[1];
3853 NFSSETHASSETFSID(nmp);
3854 *attrflagp = 1;
3855 }
3856 } else {
3857 error = nd->nd_repstat;
3858 }
3859 if (error)
3860 goto nfsmout;
3861 } else {
3862 NFSCL_REQSTART(nd, NFSPROC_FSSTAT, vp);
3863 error = nfscl_request(nd, vp, p, cred, stuff);
3864 if (error)
3865 return (error);
3866 if (nd->nd_flag & ND_NFSV3) {
3867 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3868 if (error)
3869 goto nfsmout;
3870 }
3871 if (nd->nd_repstat) {
3872 error = nd->nd_repstat;
3873 goto nfsmout;
3874 }
3875 NFSM_DISSECT(tl, u_int32_t *,
3876 NFSX_STATFS(nd->nd_flag & ND_NFSV3));
3877 }
3878 if (NFSHASNFSV3(nmp)) {
3879 sbp->sf_tbytes = fxdr_hyper(tl); tl += 2;
3880 sbp->sf_fbytes = fxdr_hyper(tl); tl += 2;
3881 sbp->sf_abytes = fxdr_hyper(tl); tl += 2;
3882 sbp->sf_tfiles = fxdr_hyper(tl); tl += 2;
3883 sbp->sf_ffiles = fxdr_hyper(tl); tl += 2;
3884 sbp->sf_afiles = fxdr_hyper(tl); tl += 2;
3885 sbp->sf_invarsec = fxdr_unsigned(u_int32_t, *tl);
3886 } else if (NFSHASNFSV4(nmp) == 0) {
3887 sbp->sf_tsize = fxdr_unsigned(u_int32_t, *tl++);
3888 sbp->sf_bsize = fxdr_unsigned(u_int32_t, *tl++);
3889 sbp->sf_blocks = fxdr_unsigned(u_int32_t, *tl++);
3890 sbp->sf_bfree = fxdr_unsigned(u_int32_t, *tl++);
3891 sbp->sf_bavail = fxdr_unsigned(u_int32_t, *tl);
3892 }
3893nfsmout:
3894 mbuf_freem(nd->nd_mrep);
3895 return (error);
3896}
3897
3898/*
3899 * nfs pathconf rpc
3900 */
3901APPLESTATIC int
3902nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc,
3903 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
3904 void *stuff)
3905{
3906 struct nfsrv_descript nfsd, *nd = &nfsd;
3907 struct nfsmount *nmp;
3908 u_int32_t *tl;
3909 nfsattrbit_t attrbits;
3910 int error;
3911
3912 *attrflagp = 0;
3913 nmp = VFSTONFS(vnode_mount(vp));
3914 if (NFSHASNFSV4(nmp)) {
3915 /*
3916 * For V4, you actually do a getattr.
3917 */
3918 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
3919 NFSPATHCONF_GETATTRBIT(&attrbits);
3920 (void) nfsrv_putattrbit(nd, &attrbits);
3921 nd->nd_flag |= ND_USEGSSNAME;
3922 error = nfscl_request(nd, vp, p, cred, stuff);
3923 if (error)
3924 return (error);
3925 if (nd->nd_repstat == 0) {
3926 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
3927 pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, p,
3928 cred);
3929 if (!error)
3930 *attrflagp = 1;
3931 } else {
3932 error = nd->nd_repstat;
3933 }
3934 } else {
3935 NFSCL_REQSTART(nd, NFSPROC_PATHCONF, vp);
3936 error = nfscl_request(nd, vp, p, cred, stuff);
3937 if (error)
3938 return (error);
3939 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3940 if (nd->nd_repstat && !error)
3941 error = nd->nd_repstat;
3942 if (!error) {
3943 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3PATHCONF);
3944 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl++);
3945 pc->pc_namemax = fxdr_unsigned(u_int32_t, *tl++);
3946 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl++);
3947 pc->pc_chownrestricted =
3948 fxdr_unsigned(u_int32_t, *tl++);
3949 pc->pc_caseinsensitive =
3950 fxdr_unsigned(u_int32_t, *tl++);
3951 pc->pc_casepreserving = fxdr_unsigned(u_int32_t, *tl);
3952 }
3953 }
3954nfsmout:
3955 mbuf_freem(nd->nd_mrep);
3956 return (error);
3957}
3958
3959/*
3960 * nfs version 3 fsinfo rpc call
3961 */
3962APPLESTATIC int
3963nfsrpc_fsinfo(vnode_t vp, struct nfsfsinfo *fsp, struct ucred *cred,
3964 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
3965{
3966 u_int32_t *tl;
3967 struct nfsrv_descript nfsd, *nd = &nfsd;
3968 int error;
3969
3970 *attrflagp = 0;
3971 NFSCL_REQSTART(nd, NFSPROC_FSINFO, vp);
3972 error = nfscl_request(nd, vp, p, cred, stuff);
3973 if (error)
3974 return (error);
3975 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
3976 if (nd->nd_repstat && !error)
3977 error = nd->nd_repstat;
3978 if (!error) {
3979 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3FSINFO);
3980 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *tl++);
3981 fsp->fs_rtpref = fxdr_unsigned(u_int32_t, *tl++);
3982 fsp->fs_rtmult = fxdr_unsigned(u_int32_t, *tl++);
3983 fsp->fs_wtmax = fxdr_unsigned(u_int32_t, *tl++);
3984 fsp->fs_wtpref = fxdr_unsigned(u_int32_t, *tl++);
3985 fsp->fs_wtmult = fxdr_unsigned(u_int32_t, *tl++);
3986 fsp->fs_dtpref = fxdr_unsigned(u_int32_t, *tl++);
3987 fsp->fs_maxfilesize = fxdr_hyper(tl);
3988 tl += 2;
3989 fxdr_nfsv3time(tl, &fsp->fs_timedelta);
3990 tl += 2;
3991 fsp->fs_properties = fxdr_unsigned(u_int32_t, *tl);
3992 }
3993nfsmout:
3994 mbuf_freem(nd->nd_mrep);
3995 return (error);
3996}
3997
3998/*
3999 * This function performs the Renew RPC.
4000 */
4001APPLESTATIC int
4002nfsrpc_renew(struct nfsclclient *clp, struct ucred *cred, NFSPROC_T *p)
4003{
4004 u_int32_t *tl;
4005 struct nfsrv_descript nfsd;
4006 struct nfsrv_descript *nd = &nfsd;
4007 struct nfsmount *nmp;
4008 int error;
4009
4010 nmp = clp->nfsc_nmp;
4011 if (nmp == NULL)
4012 return (0);
4013 nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL);
4014 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4015 *tl++ = clp->nfsc_clientid.lval[0];
4016 *tl = clp->nfsc_clientid.lval[1];
4017 nd->nd_flag |= ND_USEGSSNAME;
4018 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4019 NFS_PROG, NFS_VER4, NULL, 1, NULL);
4020 if (error)
4021 return (error);
4022 error = nd->nd_repstat;
4023 mbuf_freem(nd->nd_mrep);
4024 return (error);
4025}
4026
4027/*
4028 * This function performs the Releaselockowner RPC.
4029 */
4030APPLESTATIC int
4031nfsrpc_rellockown(struct nfsmount *nmp, struct nfscllockowner *lp,
4032 uint8_t *fh, int fhlen, struct ucred *cred, NFSPROC_T *p)
4033{
4034 struct nfsrv_descript nfsd, *nd = &nfsd;
4035 u_int32_t *tl;
4036 int error;
4037 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
4038
4039 nfscl_reqstart(nd, NFSPROC_RELEASELCKOWN, nmp, NULL, 0, NULL);
4040 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4041 *tl++ = nmp->nm_clp->nfsc_clientid.lval[0];
4042 *tl = nmp->nm_clp->nfsc_clientid.lval[1];
4043 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN);
4044 NFSBCOPY(fh, &own[NFSV4CL_LOCKNAMELEN], fhlen);
4045 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen);
4046 nd->nd_flag |= ND_USEGSSNAME;
4047 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4048 NFS_PROG, NFS_VER4, NULL, 1, NULL);
4049 if (error)
4050 return (error);
4051 error = nd->nd_repstat;
4052 mbuf_freem(nd->nd_mrep);
4053 return (error);
4054}
4055
4056/*
4057 * This function performs the Compound to get the mount pt FH.
4058 */
4059APPLESTATIC int
4060nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred,
4061 NFSPROC_T *p)
4062{
4063 u_int32_t *tl;
4064 struct nfsrv_descript nfsd;
4065 struct nfsrv_descript *nd = &nfsd;
4066 u_char *cp, *cp2;
4067 int error, cnt, len, setnil;
4068 u_int32_t *opcntp;
4069
4070 nfscl_reqstart(nd, NFSPROC_PUTROOTFH, nmp, NULL, 0, &opcntp);
4071 cp = dirpath;
4072 cnt = 0;
4073 do {
4074 setnil = 0;
4075 while (*cp == '/')
4076 cp++;
4077 cp2 = cp;
4078 while (*cp2 != '\0' && *cp2 != '/')
4079 cp2++;
4080 if (*cp2 == '/') {
4081 setnil = 1;
4082 *cp2 = '\0';
4083 }
4084 if (cp2 != cp) {
4085 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4086 *tl = txdr_unsigned(NFSV4OP_LOOKUP);
4087 nfsm_strtom(nd, cp, strlen(cp));
4088 cnt++;
4089 }
4090 if (setnil)
4091 *cp2++ = '/';
4092 cp = cp2;
4093 } while (*cp != '\0');
4094 *opcntp = txdr_unsigned(2 + cnt);
4095 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4096 *tl = txdr_unsigned(NFSV4OP_GETFH);
4097 nd->nd_flag |= ND_USEGSSNAME;
4098 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4099 NFS_PROG, NFS_VER4, NULL, 1, NULL);
4100 if (error)
4101 return (error);
4102 if (nd->nd_repstat == 0) {
4103 NFSM_DISSECT(tl, u_int32_t *, (3 + 2 * cnt) * NFSX_UNSIGNED);
4104 tl += (2 + 2 * cnt);
4105 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
4106 len > NFSX_FHMAX) {
4107 nd->nd_repstat = NFSERR_BADXDR;
4108 } else {
4109 nd->nd_repstat = nfsrv_mtostr(nd, nmp->nm_fh, len);
4110 if (nd->nd_repstat == 0)
4111 nmp->nm_fhsize = len;
4112 }
4113 }
4114 error = nd->nd_repstat;
4115nfsmout:
4116 mbuf_freem(nd->nd_mrep);
4117 return (error);
4118}
4119
4120/*
4121 * This function performs the Delegreturn RPC.
4122 */
4123APPLESTATIC int
4124nfsrpc_delegreturn(struct nfscldeleg *dp, struct ucred *cred,
4125 struct nfsmount *nmp, NFSPROC_T *p, int syscred)
4126{
4127 u_int32_t *tl;
4128 struct nfsrv_descript nfsd;
4129 struct nfsrv_descript *nd = &nfsd;
4130 int error;
4131
4132 nfscl_reqstart(nd, NFSPROC_DELEGRETURN, nmp, dp->nfsdl_fh,
4133 dp->nfsdl_fhlen, NULL);
4134 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
4135 *tl++ = dp->nfsdl_stateid.seqid;
4136 *tl++ = dp->nfsdl_stateid.other[0];
4137 *tl++ = dp->nfsdl_stateid.other[1];
4138 *tl = dp->nfsdl_stateid.other[2];
4139 if (syscred)
4140 nd->nd_flag |= ND_USEGSSNAME;
4141 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4142 NFS_PROG, NFS_VER4, NULL, 1, NULL);
4143 if (error)
4144 return (error);
4145 error = nd->nd_repstat;
4146 mbuf_freem(nd->nd_mrep);
4147 return (error);
4148}
4149
4150/*
4151 * nfs getacl call.
4152 */
4153APPLESTATIC int
4154nfsrpc_getacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
4155 struct acl *aclp, void *stuff)
4156{
4157 struct nfsrv_descript nfsd, *nd = &nfsd;
4158 int error;
4159 nfsattrbit_t attrbits;
4160 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
4161
4162 if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp))
4163 return (EOPNOTSUPP);
4164 NFSCL_REQSTART(nd, NFSPROC_GETACL, vp);
4165 NFSZERO_ATTRBIT(&attrbits);
4166 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
4167 (void) nfsrv_putattrbit(nd, &attrbits);
4168 error = nfscl_request(nd, vp, p, cred, stuff);
4169 if (error)
4170 return (error);
4171 if (!nd->nd_repstat)
4172 error = nfsv4_loadattr(nd, vp, NULL, NULL, NULL, 0, NULL,
4173 NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, p, cred);
4174 else
4175 error = nd->nd_repstat;
4176 mbuf_freem(nd->nd_mrep);
4177 return (error);
4178}
4179
4180/*
4181 * nfs setacl call.
4182 */
4183APPLESTATIC int
4184nfsrpc_setacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
4185 struct acl *aclp, void *stuff)
4186{
4187 int error;
4188 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
4189
4190 if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp))
4191 return (EOPNOTSUPP);
4192 error = nfsrpc_setattr(vp, NULL, aclp, cred, p, NULL, NULL, stuff);
4193 return (error);
4194}
4195
4196/*
4197 * nfs setacl call.
4198 */
4199static int
4200nfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
4201 struct acl *aclp, nfsv4stateid_t *stateidp, void *stuff)
4202{
4203 struct nfsrv_descript nfsd, *nd = &nfsd;
4204 int error;
4205 nfsattrbit_t attrbits;
4206 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
4207
4208 if (!NFSHASNFSV4(nmp))
4209 return (EOPNOTSUPP);
4210 NFSCL_REQSTART(nd, NFSPROC_SETACL, vp);
4211 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
4212 NFSZERO_ATTRBIT(&attrbits);
4213 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
4214 (void) nfsv4_fillattr(nd, vnode_mount(vp), vp, aclp, NULL, NULL, 0,
4215 &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0);
4216 error = nfscl_request(nd, vp, p, cred, stuff);
4217 if (error)
4218 return (error);
4219 /* Don't care about the pre/postop attributes */
4220 mbuf_freem(nd->nd_mrep);
4221 return (nd->nd_repstat);
4222}