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