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