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