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