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