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