1 /*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Rick Macklem at The University of Guelph.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 */
35
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38
39 /*
40 * Rpc op calls, generally called from the vnode op calls or through the
41 * buffer cache, for NFS v2, 3 and 4.
42 * These do not normally make any changes to vnode arguments or use
43 * structures that might change between the VFS variants. The returned
44 * arguments are all at the end, after the NFSPROC_T *p one.
45 */
46
47 #include "opt_inet6.h"
48
49 #include <fs/nfs/nfsport.h>
50 #include <fs/nfsclient/nfs.h>
51 #include <sys/extattr.h>
52 #include <sys/sysctl.h>
53 #include <sys/taskqueue.h>
54
55 SYSCTL_DECL(_vfs_nfs);
56
57 static int nfsignore_eexist = 0;
58 SYSCTL_INT(_vfs_nfs, OID_AUTO, ignore_eexist, CTLFLAG_RW,
59 &nfsignore_eexist, 0, "NFS ignore EEXIST replies for mkdir/symlink");
60
61 static int nfscl_dssameconn = 0;
62 SYSCTL_INT(_vfs_nfs, OID_AUTO, dssameconn, CTLFLAG_RW,
63 &nfscl_dssameconn, 0, "Use same TCP connection to multiple DSs");
64
65 static uint64_t nfs_maxcopyrange = SSIZE_MAX;
66 SYSCTL_U64(_vfs_nfs, OID_AUTO, maxcopyrange, CTLFLAG_RW,
67 &nfs_maxcopyrange, 0, "Max size of a Copy so RPC times reasonable");
68
69 /*
70 * Global variables
71 */
72 extern struct nfsstatsv1 nfsstatsv1;
73 extern int nfs_numnfscbd;
74 extern struct timeval nfsboottime;
75 extern u_int32_t newnfs_false, newnfs_true;
76 extern nfstype nfsv34_type[9];
77 extern int nfsrv_useacl;
78 extern char nfsv4_callbackaddr[INET6_ADDRSTRLEN];
79 extern int nfscl_debuglevel;
80 extern int nfs_pnfsiothreads;
81 extern u_long sb_max_adj;
82 NFSCLSTATEMUTEX;
83 int nfstest_outofseq = 0;
84 int nfscl_assumeposixlocks = 1;
85 int nfscl_enablecallb = 0;
86 short nfsv4_cbport = NFSV4_CBPORT;
87 int nfstest_openallsetattr = 0;
88
89 #define DIRHDSIZ offsetof(struct dirent, d_name)
90
91 /*
92 * nfscl_getsameserver() can return one of three values:
93 * NFSDSP_USETHISSESSION - Use this session for the DS.
94 * NFSDSP_SEQTHISSESSION - Use the nfsclds_sequence field of this dsp for new
95 * session.
96 * NFSDSP_NOTFOUND - No matching server was found.
97 */
98 enum nfsclds_state {
99 NFSDSP_USETHISSESSION = 0,
100 NFSDSP_SEQTHISSESSION = 1,
101 NFSDSP_NOTFOUND = 2,
102 };
103
104 /*
105 * Do a write RPC on a DS data file, using this structure for the arguments,
106 * so that this function can be executed by a separate kernel process.
107 */
108 struct nfsclwritedsdorpc {
109 int done;
110 int inprog;
111 struct task tsk;
112 struct vnode *vp;
113 int iomode;
114 int must_commit;
115 nfsv4stateid_t *stateidp;
116 struct nfsclds *dsp;
117 uint64_t off;
118 int len;
119 #ifdef notyet
120 int advise;
121 #endif
122 struct nfsfh *fhp;
123 struct mbuf *m;
124 int vers;
125 int minorvers;
126 struct ucred *cred;
127 NFSPROC_T *p;
128 int err;
129 };
130
131 static int nfsrpc_setattrrpc(vnode_t , struct vattr *, nfsv4stateid_t *,
132 struct ucred *, NFSPROC_T *, struct nfsvattr *, int *);
133 static int nfsrpc_readrpc(vnode_t , struct uio *, struct ucred *,
134 nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *);
135 static int nfsrpc_writerpc(vnode_t , struct uio *, int *, int *,
136 struct ucred *, nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *,
137 int);
138 static int nfsrpc_deallocaterpc(vnode_t, off_t, off_t, nfsv4stateid_t *,
139 struct nfsvattr *, int *, struct ucred *, NFSPROC_T *);
140 static int nfsrpc_createv23(vnode_t , char *, int, struct vattr *,
141 nfsquad_t, int, struct ucred *, NFSPROC_T *, struct nfsvattr *,
142 struct nfsvattr *, struct nfsfh **, int *, int *);
143 static int nfsrpc_createv4(vnode_t , char *, int, struct vattr *,
144 nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, struct ucred *,
145 NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, struct nfsfh **, int *,
146 int *, int *);
147 static int nfsrpc_locku(struct nfsrv_descript *, struct nfsmount *,
148 struct nfscllockowner *, u_int64_t, u_int64_t,
149 u_int32_t, struct ucred *, NFSPROC_T *, int);
150 static int nfsrpc_setaclrpc(vnode_t, struct ucred *, NFSPROC_T *,
151 struct acl *, nfsv4stateid_t *);
152 static int nfsrpc_layouterror(struct nfsmount *, uint8_t *, int, uint64_t,
153 uint64_t, nfsv4stateid_t *, struct ucred *, NFSPROC_T *, uint32_t,
154 uint32_t, char *);
155 static int nfsrpc_getlayout(struct nfsmount *, vnode_t, struct nfsfh *, int,
156 uint32_t, uint32_t *, nfsv4stateid_t *, uint64_t, struct nfscllayout **,
157 struct ucred *, NFSPROC_T *);
158 static int nfsrpc_fillsa(struct nfsmount *, struct sockaddr_in *,
159 struct sockaddr_in6 *, sa_family_t, int, int, struct nfsclds **,
160 NFSPROC_T *);
161 static void nfscl_initsessionslots(struct nfsclsession *);
162 static int nfscl_doflayoutio(vnode_t, struct uio *, int *, int *, int *,
163 nfsv4stateid_t *, int, struct nfscldevinfo *, struct nfscllayout *,
164 struct nfsclflayout *, uint64_t, uint64_t, int, struct ucred *,
165 NFSPROC_T *);
166 static int nfscl_dofflayoutio(vnode_t, struct uio *, int *, int *, int *,
167 nfsv4stateid_t *, int, struct nfscldevinfo *, struct nfscllayout *,
168 struct nfsclflayout *, uint64_t, uint64_t, int, int, struct mbuf *,
169 struct nfsclwritedsdorpc *, struct ucred *, NFSPROC_T *);
170 static int nfsrpc_readds(vnode_t, struct uio *, nfsv4stateid_t *, int *,
171 struct nfsclds *, uint64_t, int, struct nfsfh *, int, int, int,
172 struct ucred *, NFSPROC_T *);
173 static int nfsrpc_writeds(vnode_t, struct uio *, int *, int *,
174 nfsv4stateid_t *, struct nfsclds *, uint64_t, int,
175 struct nfsfh *, int, int, int, int, struct ucred *, NFSPROC_T *);
176 static int nfsio_writedsmir(vnode_t, int *, int *, nfsv4stateid_t *,
177 struct nfsclds *, uint64_t, int, struct nfsfh *, struct mbuf *, int, int,
178 struct nfsclwritedsdorpc *, struct ucred *, NFSPROC_T *);
179 static int nfsrpc_writedsmir(vnode_t, int *, int *, nfsv4stateid_t *,
180 struct nfsclds *, uint64_t, int, struct nfsfh *, struct mbuf *, int, int,
181 struct ucred *, NFSPROC_T *);
182 static enum nfsclds_state nfscl_getsameserver(struct nfsmount *,
183 struct nfsclds *, struct nfsclds **, uint32_t *);
184 static int nfsio_commitds(vnode_t, uint64_t, int, struct nfsclds *,
185 struct nfsfh *, int, int, struct nfsclwritedsdorpc *, struct ucred *,
186 NFSPROC_T *);
187 static int nfsrpc_commitds(vnode_t, uint64_t, int, struct nfsclds *,
188 struct nfsfh *, int, int, struct ucred *, NFSPROC_T *);
189 #ifdef notyet
190 static int nfsio_adviseds(vnode_t, uint64_t, int, int, struct nfsclds *,
191 struct nfsfh *, int, int, struct nfsclwritedsdorpc *, struct ucred *,
192 NFSPROC_T *);
193 static int nfsrpc_adviseds(vnode_t, uint64_t, int, int, struct nfsclds *,
194 struct nfsfh *, int, int, struct ucred *, NFSPROC_T *);
195 #endif
196 static int nfsrpc_allocaterpc(vnode_t, off_t, off_t, nfsv4stateid_t *,
197 struct nfsvattr *, int *, struct ucred *, NFSPROC_T *);
198 static void nfsrv_setuplayoutget(struct nfsrv_descript *, int, uint64_t,
199 uint64_t, uint64_t, nfsv4stateid_t *, int, int, int);
200 static int nfsrv_parseug(struct nfsrv_descript *, int, uid_t *, gid_t *,
201 NFSPROC_T *);
202 static int nfsrv_parselayoutget(struct nfsmount *, struct nfsrv_descript *,
203 nfsv4stateid_t *, int *, struct nfsclflayouthead *);
204 static int nfsrpc_getopenlayout(struct nfsmount *, vnode_t, u_int8_t *,
205 int, uint8_t *, int, uint32_t, struct nfsclopen *, uint8_t *, int,
206 struct nfscldeleg **, struct ucred *, NFSPROC_T *);
207 static int nfsrpc_getcreatelayout(vnode_t, char *, int, struct vattr *,
208 nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **,
209 struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *,
210 struct nfsfh **, int *, int *, int *);
211 static int nfsrpc_openlayoutrpc(struct nfsmount *, vnode_t, u_int8_t *,
212 int, uint8_t *, int, uint32_t, struct nfsclopen *, uint8_t *, int,
213 struct nfscldeleg **, nfsv4stateid_t *, int, int, int, int *,
214 struct nfsclflayouthead *, int *, struct ucred *, NFSPROC_T *);
215 static int nfsrpc_createlayout(vnode_t, char *, int, struct vattr *,
216 nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **,
217 struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *,
218 struct nfsfh **, int *, int *, int *, nfsv4stateid_t *,
219 int, int, int, int *, struct nfsclflayouthead *, int *);
220 static int nfsrpc_layoutget(struct nfsmount *, uint8_t *, int, int, uint64_t,
221 uint64_t, uint64_t, int, int, nfsv4stateid_t *, int *,
222 struct nfsclflayouthead *, struct ucred *, NFSPROC_T *);
223 static int nfsrpc_layoutgetres(struct nfsmount *, vnode_t, uint8_t *,
224 int, nfsv4stateid_t *, int, uint32_t *, struct nfscllayout **,
225 struct nfsclflayouthead *, int, int, int *, struct ucred *, NFSPROC_T *);
226 static int nfsrpc_copyrpc(vnode_t, off_t, vnode_t, off_t, size_t *,
227 nfsv4stateid_t *, nfsv4stateid_t *, struct nfsvattr *, int *,
228 struct nfsvattr *, int *, bool, int *, struct ucred *, NFSPROC_T *);
229 static int nfsrpc_seekrpc(vnode_t, off_t *, nfsv4stateid_t *, bool *,
230 int, struct nfsvattr *, int *, struct ucred *);
231 static struct mbuf *nfsm_split(struct mbuf *, uint64_t);
232
233 int nfs_pnfsio(task_fn_t *, void *);
234
235 /*
236 * nfs null call from vfs.
237 */
238 int
239 nfsrpc_null(vnode_t vp, struct ucred *cred, NFSPROC_T *p)
240 {
241 int error;
242 struct nfsrv_descript nfsd, *nd = &nfsd;
243
244 NFSCL_REQSTART(nd, NFSPROC_NULL, vp, NULL);
245 error = nfscl_request(nd, vp, p, cred);
246 if (nd->nd_repstat && !error)
247 error = nd->nd_repstat;
248 m_freem(nd->nd_mrep);
249 return (error);
250 }
251
252 /*
253 * nfs access rpc op.
254 * For nfs version 3 and 4, use the access rpc to check accessibility. If file
255 * modes are changed on the server, accesses might still fail later.
256 */
257 int
258 nfsrpc_access(vnode_t vp, int acmode, struct ucred *cred,
259 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp)
260 {
261 int error;
262 u_int32_t mode, rmode;
263
264 if (acmode & VREAD)
265 mode = NFSACCESS_READ;
266 else
267 mode = 0;
268 if (vp->v_type == VDIR) {
269 if (acmode & VWRITE)
270 mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND |
271 NFSACCESS_DELETE);
272 if (acmode & VEXEC)
273 mode |= NFSACCESS_LOOKUP;
274 } else {
275 if (acmode & VWRITE)
276 mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND);
277 if (acmode & VEXEC)
278 mode |= NFSACCESS_EXECUTE;
279 }
280
281 /*
282 * Now, just call nfsrpc_accessrpc() to do the actual RPC.
283 */
284 error = nfsrpc_accessrpc(vp, mode, cred, p, nap, attrflagp, &rmode);
285
286 /*
287 * The NFS V3 spec does not clarify whether or not
288 * the returned access bits can be a superset of
289 * the ones requested, so...
290 */
291 if (!error && (rmode & mode) != mode)
292 error = EACCES;
293 return (error);
294 }
295
296 /*
297 * The actual rpc, separated out for Darwin.
298 */
299 int
300 nfsrpc_accessrpc(vnode_t vp, u_int32_t mode, struct ucred *cred,
301 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, u_int32_t *rmodep)
302 {
303 u_int32_t *tl;
304 u_int32_t supported, rmode;
305 int error;
306 struct nfsrv_descript nfsd, *nd = &nfsd;
307 nfsattrbit_t attrbits;
308
309 *attrflagp = 0;
310 supported = mode;
311 NFSCL_REQSTART(nd, NFSPROC_ACCESS, vp, cred);
312 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
313 *tl = txdr_unsigned(mode);
314 if (nd->nd_flag & ND_NFSV4) {
315 /*
316 * And do a Getattr op.
317 */
318 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
319 *tl = txdr_unsigned(NFSV4OP_GETATTR);
320 NFSGETATTR_ATTRBIT(&attrbits);
321 (void) nfsrv_putattrbit(nd, &attrbits);
322 }
323 error = nfscl_request(nd, vp, p, cred);
324 if (error)
325 return (error);
326 if (nd->nd_flag & ND_NFSV3) {
327 error = nfscl_postop_attr(nd, nap, attrflagp);
328 if (error)
329 goto nfsmout;
330 }
331 if (!nd->nd_repstat) {
332 if (nd->nd_flag & ND_NFSV4) {
333 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
334 supported = fxdr_unsigned(u_int32_t, *tl++);
335 } else {
336 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
337 }
338 rmode = fxdr_unsigned(u_int32_t, *tl);
339 if (nd->nd_flag & ND_NFSV4)
340 error = nfscl_postop_attr(nd, nap, attrflagp);
341
342 /*
343 * It's not obvious what should be done about
344 * unsupported access modes. For now, be paranoid
345 * and clear the unsupported ones.
346 */
347 rmode &= supported;
348 *rmodep = rmode;
349 } else
350 error = nd->nd_repstat;
351 nfsmout:
352 m_freem(nd->nd_mrep);
353 return (error);
354 }
355
356 /*
357 * nfs open rpc
358 */
359 int
360 nfsrpc_open(vnode_t vp, int amode, struct ucred *cred, NFSPROC_T *p)
361 {
362 struct nfsclopen *op;
363 struct nfscldeleg *dp;
364 struct nfsfh *nfhp;
365 struct nfsnode *np = VTONFS(vp);
366 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
367 u_int32_t mode, clidrev;
368 int ret, newone, error, expireret = 0, retrycnt;
369
370 /*
371 * For NFSv4, Open Ops are only done on Regular Files.
372 */
373 if (vp->v_type != VREG)
374 return (0);
375 mode = 0;
376 if (amode & FREAD)
377 mode |= NFSV4OPEN_ACCESSREAD;
378 if (amode & FWRITE)
379 mode |= NFSV4OPEN_ACCESSWRITE;
380 nfhp = np->n_fhp;
381
382 retrycnt = 0;
383 #ifdef notdef
384 { char name[100]; int namel;
385 namel = (np->n_v4->n4_namelen < 100) ? np->n_v4->n4_namelen : 99;
386 bcopy(NFS4NODENAME(np->n_v4), name, namel);
387 name[namel] = '\0';
388 printf("rpcopen p=0x%x name=%s",p->p_pid,name);
389 if (nfhp->nfh_len > 0) printf(" fh=0x%x\n",nfhp->nfh_fh[12]);
390 else printf(" fhl=0\n");
391 }
392 #endif
393 do {
394 dp = NULL;
395 error = nfscl_open(vp, nfhp->nfh_fh, nfhp->nfh_len, mode, 1,
396 cred, p, NULL, &op, &newone, &ret, 1, true);
397 if (error) {
398 return (error);
399 }
400 if (nmp->nm_clp != NULL)
401 clidrev = nmp->nm_clp->nfsc_clientidrev;
402 else
403 clidrev = 0;
404 if (ret == NFSCLOPEN_DOOPEN) {
405 if (np->n_v4 != NULL) {
406 /*
407 * For the first attempt, try and get a layout, if
408 * pNFS is enabled for the mount.
409 */
410 if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 ||
411 nfs_numnfscbd == 0 ||
412 (np->n_flag & NNOLAYOUT) != 0 || retrycnt > 0)
413 error = nfsrpc_openrpc(nmp, vp,
414 np->n_v4->n4_data,
415 np->n_v4->n4_fhlen, np->n_fhp->nfh_fh,
416 np->n_fhp->nfh_len, mode, op,
417 NFS4NODENAME(np->n_v4),
418 np->n_v4->n4_namelen,
419 &dp, 0, 0x0, cred, p, 0, 0);
420 else
421 error = nfsrpc_getopenlayout(nmp, vp,
422 np->n_v4->n4_data,
423 np->n_v4->n4_fhlen, np->n_fhp->nfh_fh,
424 np->n_fhp->nfh_len, mode, op,
425 NFS4NODENAME(np->n_v4),
426 np->n_v4->n4_namelen, &dp, cred, p);
427 if (dp != NULL) {
428 NFSLOCKNODE(np);
429 np->n_flag &= ~NDELEGMOD;
430 /*
431 * Invalidate the attribute cache, so that
432 * attributes that pre-date the issue of a
433 * delegation are not cached, since the
434 * cached attributes will remain valid while
435 * the delegation is held.
436 */
437 NFSINVALATTRCACHE(np);
438 NFSUNLOCKNODE(np);
439 (void) nfscl_deleg(nmp->nm_mountp,
440 op->nfso_own->nfsow_clp,
441 nfhp->nfh_fh, nfhp->nfh_len, cred, p, &dp);
442 }
443 } else {
444 error = EIO;
445 }
446 newnfs_copyincred(cred, &op->nfso_cred);
447 } else if (ret == NFSCLOPEN_SETCRED)
448 /*
449 * This is a new local open on a delegation. It needs
450 * to have credentials so that an open can be done
451 * against the server during recovery.
452 */
453 newnfs_copyincred(cred, &op->nfso_cred);
454
455 /*
456 * nfso_opencnt is the count of how many VOP_OPEN()s have
457 * been done on this Open successfully and a VOP_CLOSE()
458 * is expected for each of these.
459 * If error is non-zero, don't increment it, since the Open
460 * hasn't succeeded yet.
461 */
462 if (!error) {
463 op->nfso_opencnt++;
464 if (NFSHASNFSV4N(nmp) && NFSHASONEOPENOWN(nmp)) {
465 NFSLOCKNODE(np);
466 np->n_openstateid = op;
467 NFSUNLOCKNODE(np);
468 }
469 }
470 nfscl_openrelease(nmp, op, error, newone);
471 if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
472 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
473 error == NFSERR_BADSESSION) {
474 (void) nfs_catnap(PZERO, error, "nfs_open");
475 } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID)
476 && clidrev != 0) {
477 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
478 retrycnt++;
479 }
480 } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
481 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
482 error == NFSERR_BADSESSION ||
483 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
484 expireret == 0 && clidrev != 0 && retrycnt < 4));
485 if (error && retrycnt >= 4)
486 error = EIO;
487 return (error);
488 }
489
490 /*
491 * the actual open rpc
492 */
493 int
494 nfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen,
495 u_int8_t *newfhp, int newfhlen, u_int32_t mode, struct nfsclopen *op,
496 u_int8_t *name, int namelen, struct nfscldeleg **dpp,
497 int reclaim, u_int32_t delegtype, struct ucred *cred, NFSPROC_T *p,
498 int syscred, int recursed)
499 {
500 u_int32_t *tl;
501 struct nfsrv_descript nfsd, *nd = &nfsd;
502 struct nfscldeleg *dp, *ndp = NULL;
503 struct nfsvattr nfsva;
504 u_int32_t rflags, deleg;
505 nfsattrbit_t attrbits;
506 int error, ret, acesize, limitby;
507 struct nfsclsession *tsep;
508
509 dp = *dpp;
510 *dpp = NULL;
511 nfscl_reqstart(nd, NFSPROC_OPEN, nmp, nfhp, fhlen, NULL, NULL, 0, 0,
512 cred);
513 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
514 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
515 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
516 *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
517 tsep = nfsmnt_mdssession(nmp);
518 *tl++ = tsep->nfsess_clientid.lval[0];
519 *tl = tsep->nfsess_clientid.lval[1];
520 (void) nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN);
521 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
522 *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE);
523 if (reclaim) {
524 *tl = txdr_unsigned(NFSV4OPEN_CLAIMPREVIOUS);
525 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
526 *tl = txdr_unsigned(delegtype);
527 } else {
528 if (dp != NULL) {
529 *tl = txdr_unsigned(NFSV4OPEN_CLAIMDELEGATECUR);
530 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
531 if (NFSHASNFSV4N(nmp))
532 *tl++ = 0;
533 else
534 *tl++ = dp->nfsdl_stateid.seqid;
535 *tl++ = dp->nfsdl_stateid.other[0];
536 *tl++ = dp->nfsdl_stateid.other[1];
537 *tl = dp->nfsdl_stateid.other[2];
538 } else {
539 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
540 }
541 (void) nfsm_strtom(nd, name, namelen);
542 }
543 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
544 *tl = txdr_unsigned(NFSV4OP_GETATTR);
545 NFSZERO_ATTRBIT(&attrbits);
546 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
547 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY);
548 (void) nfsrv_putattrbit(nd, &attrbits);
549 if (syscred)
550 nd->nd_flag |= ND_USEGSSNAME;
551 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
552 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
553 if (error)
554 return (error);
555 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
556 if (!nd->nd_repstat) {
557 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
558 6 * NFSX_UNSIGNED);
559 op->nfso_stateid.seqid = *tl++;
560 op->nfso_stateid.other[0] = *tl++;
561 op->nfso_stateid.other[1] = *tl++;
562 op->nfso_stateid.other[2] = *tl;
563 rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
564 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
565 if (error)
566 goto nfsmout;
567 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
568 deleg = fxdr_unsigned(u_int32_t, *tl);
569 if (deleg == NFSV4OPEN_DELEGATEREAD ||
570 deleg == NFSV4OPEN_DELEGATEWRITE) {
571 if (!(op->nfso_own->nfsow_clp->nfsc_flags &
572 NFSCLFLAGS_FIRSTDELEG))
573 op->nfso_own->nfsow_clp->nfsc_flags |=
574 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
575 ndp = malloc(
576 sizeof (struct nfscldeleg) + newfhlen,
577 M_NFSCLDELEG, M_WAITOK);
578 LIST_INIT(&ndp->nfsdl_owner);
579 LIST_INIT(&ndp->nfsdl_lock);
580 ndp->nfsdl_clp = op->nfso_own->nfsow_clp;
581 ndp->nfsdl_fhlen = newfhlen;
582 NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen);
583 newnfs_copyincred(cred, &ndp->nfsdl_cred);
584 nfscl_lockinit(&ndp->nfsdl_rwlock);
585 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
586 NFSX_UNSIGNED);
587 ndp->nfsdl_stateid.seqid = *tl++;
588 ndp->nfsdl_stateid.other[0] = *tl++;
589 ndp->nfsdl_stateid.other[1] = *tl++;
590 ndp->nfsdl_stateid.other[2] = *tl++;
591 ret = fxdr_unsigned(int, *tl);
592 if (deleg == NFSV4OPEN_DELEGATEWRITE) {
593 ndp->nfsdl_flags = NFSCLDL_WRITE;
594 /*
595 * Indicates how much the file can grow.
596 */
597 NFSM_DISSECT(tl, u_int32_t *,
598 3 * NFSX_UNSIGNED);
599 limitby = fxdr_unsigned(int, *tl++);
600 switch (limitby) {
601 case NFSV4OPEN_LIMITSIZE:
602 ndp->nfsdl_sizelimit = fxdr_hyper(tl);
603 break;
604 case NFSV4OPEN_LIMITBLOCKS:
605 ndp->nfsdl_sizelimit =
606 fxdr_unsigned(u_int64_t, *tl++);
607 ndp->nfsdl_sizelimit *=
608 fxdr_unsigned(u_int64_t, *tl);
609 break;
610 default:
611 error = NFSERR_BADXDR;
612 goto nfsmout;
613 }
614 } else {
615 ndp->nfsdl_flags = NFSCLDL_READ;
616 }
617 if (ret)
618 ndp->nfsdl_flags |= NFSCLDL_RECALL;
619 error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, false,
620 &ret, &acesize, p);
621 if (error)
622 goto nfsmout;
623 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
624 error = NFSERR_BADXDR;
625 goto nfsmout;
626 }
627 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
628 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
629 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
630 NULL, NULL, NULL, p, cred);
631 if (error)
632 goto nfsmout;
633 if (ndp != NULL) {
634 ndp->nfsdl_change = nfsva.na_filerev;
635 ndp->nfsdl_modtime = nfsva.na_mtime;
636 ndp->nfsdl_flags |= NFSCLDL_MODTIMESET;
637 }
638 if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM)) {
639 do {
640 ret = nfsrpc_openconfirm(vp, newfhp, newfhlen, op,
641 cred, p);
642 if (ret == NFSERR_DELAY)
643 (void) nfs_catnap(PZERO, ret, "nfs_open");
644 } while (ret == NFSERR_DELAY);
645 error = ret;
646 }
647 if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) ||
648 nfscl_assumeposixlocks)
649 op->nfso_posixlock = 1;
650 else
651 op->nfso_posixlock = 0;
652
653 /*
654 * If the server is handing out delegations, but we didn't
655 * get one because an OpenConfirm was required, try the
656 * Open again, to get a delegation. This is a harmless no-op,
657 * from a server's point of view.
658 */
659 if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM) &&
660 (op->nfso_own->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG)
661 && !error && dp == NULL && ndp == NULL && !recursed) {
662 do {
663 ret = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp,
664 newfhlen, mode, op, name, namelen, &ndp, 0, 0x0,
665 cred, p, syscred, 1);
666 if (ret == NFSERR_DELAY)
667 (void) nfs_catnap(PZERO, ret, "nfs_open2");
668 } while (ret == NFSERR_DELAY);
669 if (ret) {
670 if (ndp != NULL) {
671 free(ndp, M_NFSCLDELEG);
672 ndp = NULL;
673 }
674 if (ret == NFSERR_STALECLIENTID ||
675 ret == NFSERR_STALEDONTRECOVER ||
676 ret == NFSERR_BADSESSION)
677 error = ret;
678 }
679 }
680 }
681 if (nd->nd_repstat != 0 && error == 0)
682 error = nd->nd_repstat;
683 if (error == NFSERR_STALECLIENTID)
684 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
685 nfsmout:
686 if (!error)
687 *dpp = ndp;
688 else if (ndp != NULL)
689 free(ndp, M_NFSCLDELEG);
690 m_freem(nd->nd_mrep);
691 return (error);
692 }
693
694 /*
695 * open downgrade rpc
696 */
697 int
698 nfsrpc_opendowngrade(vnode_t vp, u_int32_t mode, struct nfsclopen *op,
699 struct ucred *cred, NFSPROC_T *p)
700 {
701 u_int32_t *tl;
702 struct nfsrv_descript nfsd, *nd = &nfsd;
703 int error;
704
705 NFSCL_REQSTART(nd, NFSPROC_OPENDOWNGRADE, vp, cred);
706 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
707 if (NFSHASNFSV4N(VFSTONFS(vp->v_mount)))
708 *tl++ = 0;
709 else
710 *tl++ = op->nfso_stateid.seqid;
711 *tl++ = op->nfso_stateid.other[0];
712 *tl++ = op->nfso_stateid.other[1];
713 *tl++ = op->nfso_stateid.other[2];
714 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
715 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
716 *tl = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
717 error = nfscl_request(nd, vp, p, cred);
718 if (error)
719 return (error);
720 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
721 if (!nd->nd_repstat) {
722 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
723 op->nfso_stateid.seqid = *tl++;
724 op->nfso_stateid.other[0] = *tl++;
725 op->nfso_stateid.other[1] = *tl++;
726 op->nfso_stateid.other[2] = *tl;
727 }
728 if (nd->nd_repstat && error == 0)
729 error = nd->nd_repstat;
730 if (error == NFSERR_STALESTATEID)
731 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
732 nfsmout:
733 m_freem(nd->nd_mrep);
734 return (error);
735 }
736
737 /*
738 * V4 Close operation.
739 */
740 int
741 nfsrpc_close(vnode_t vp, int doclose, NFSPROC_T *p)
742 {
743 struct nfsclclient *clp;
744 int error;
745
746 if (vp->v_type != VREG)
747 return (0);
748 if (doclose)
749 error = nfscl_doclose(vp, &clp, p);
750 else {
751 error = nfscl_getclose(vp, &clp);
752 if (error == 0)
753 nfscl_clientrelease(clp);
754 }
755 return (error);
756 }
757
758 /*
759 * Close the open.
760 */
761 int
762 nfsrpc_doclose(struct nfsmount *nmp, struct nfsclopen *op, NFSPROC_T *p,
763 bool loop_on_delayed, bool freeop)
764 {
765 struct nfsrv_descript nfsd, *nd = &nfsd;
766 struct nfscllockowner *lp, *nlp;
767 struct nfscllock *lop, *nlop;
768 struct ucred *tcred;
769 u_int64_t off = 0, len = 0;
770 u_int32_t type = NFSV4LOCKT_READ;
771 int error, do_unlock, trycnt;
772
773 tcred = newnfs_getcred();
774 newnfs_copycred(&op->nfso_cred, tcred);
775 /*
776 * (Theoretically this could be done in the same
777 * compound as the close, but having multiple
778 * sequenced Ops in the same compound might be
779 * too scary for some servers.)
780 */
781 if (op->nfso_posixlock) {
782 off = 0;
783 len = NFS64BITSSET;
784 type = NFSV4LOCKT_READ;
785 }
786
787 /*
788 * Since this function is only called from VOP_INACTIVE(), no
789 * other thread will be manipulating this Open. As such, the
790 * lock lists are not being changed by other threads, so it should
791 * be safe to do this without locking.
792 */
793 LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) {
794 do_unlock = 1;
795 LIST_FOREACH_SAFE(lop, &lp->nfsl_lock, nfslo_list, nlop) {
796 if (op->nfso_posixlock == 0) {
797 off = lop->nfslo_first;
798 len = lop->nfslo_end - lop->nfslo_first;
799 if (lop->nfslo_type == F_WRLCK)
800 type = NFSV4LOCKT_WRITE;
801 else
802 type = NFSV4LOCKT_READ;
803 }
804 if (do_unlock) {
805 trycnt = 0;
806 do {
807 error = nfsrpc_locku(nd, nmp, lp, off,
808 len, type, tcred, p, 0);
809 if ((nd->nd_repstat == NFSERR_GRACE ||
810 nd->nd_repstat == NFSERR_DELAY) &&
811 error == 0)
812 (void) nfs_catnap(PZERO,
813 (int)nd->nd_repstat,
814 "nfs_close");
815 } while ((nd->nd_repstat == NFSERR_GRACE ||
816 nd->nd_repstat == NFSERR_DELAY) &&
817 error == 0 && trycnt++ < 5);
818 if (op->nfso_posixlock)
819 do_unlock = 0;
820 }
821 nfscl_freelock(lop, 0);
822 }
823 /*
824 * Do a ReleaseLockOwner.
825 * The lock owner name nfsl_owner may be used by other opens for
826 * other files but the lock_owner4 name that nfsrpc_rellockown()
827 * puts on the wire has the file handle for this file appended
828 * to it, so it can be done now.
829 */
830 (void)nfsrpc_rellockown(nmp, lp, lp->nfsl_open->nfso_fh,
831 lp->nfsl_open->nfso_fhlen, tcred, p);
832 }
833
834 /*
835 * There could be other Opens for different files on the same
836 * OpenOwner, so locking is required.
837 */
838 NFSLOCKCLSTATE();
839 nfscl_lockexcl(&op->nfso_own->nfsow_rwlock, NFSCLSTATEMUTEXPTR);
840 NFSUNLOCKCLSTATE();
841 do {
842 error = nfscl_tryclose(op, tcred, nmp, p, loop_on_delayed);
843 if (error == NFSERR_GRACE)
844 (void) nfs_catnap(PZERO, error, "nfs_close");
845 } while (error == NFSERR_GRACE);
846 NFSLOCKCLSTATE();
847 nfscl_lockunlock(&op->nfso_own->nfsow_rwlock);
848
849 LIST_FOREACH_SAFE(lp, &op->nfso_lock, nfsl_list, nlp)
850 nfscl_freelockowner(lp, 0);
851 if (freeop && error != NFSERR_DELAY)
852 nfscl_freeopen(op, 0, true);
853 NFSUNLOCKCLSTATE();
854 NFSFREECRED(tcred);
855 return (error);
856 }
857
858 /*
859 * The actual Close RPC.
860 */
861 int
862 nfsrpc_closerpc(struct nfsrv_descript *nd, struct nfsmount *nmp,
863 struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p,
864 int syscred)
865 {
866 u_int32_t *tl;
867 int error;
868
869 nfscl_reqstart(nd, NFSPROC_CLOSE, nmp, op->nfso_fh,
870 op->nfso_fhlen, NULL, NULL, 0, 0, cred);
871 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
872 if (NFSHASNFSV4N(nmp)) {
873 *tl++ = 0;
874 *tl++ = 0;
875 } else {
876 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
877 *tl++ = op->nfso_stateid.seqid;
878 }
879 *tl++ = op->nfso_stateid.other[0];
880 *tl++ = op->nfso_stateid.other[1];
881 *tl = op->nfso_stateid.other[2];
882 if (syscred)
883 nd->nd_flag |= ND_USEGSSNAME;
884 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
885 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
886 if (error)
887 return (error);
888 if (!NFSHASNFSV4N(nmp))
889 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
890 if (nd->nd_repstat == 0)
891 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
892 error = nd->nd_repstat;
893 if (!NFSHASNFSV4N(nmp) && error == NFSERR_STALESTATEID)
894 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
895 nfsmout:
896 m_freem(nd->nd_mrep);
897 return (error);
898 }
899
900 /*
901 * V4 Open Confirm RPC.
902 */
903 int
904 nfsrpc_openconfirm(vnode_t vp, u_int8_t *nfhp, int fhlen,
905 struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p)
906 {
907 u_int32_t *tl;
908 struct nfsrv_descript nfsd, *nd = &nfsd;
909 struct nfsmount *nmp;
910 int error;
911
912 nmp = VFSTONFS(vp->v_mount);
913 if (NFSHASNFSV4N(nmp))
914 return (0); /* No confirmation for NFSv4.1. */
915 nfscl_reqstart(nd, NFSPROC_OPENCONFIRM, nmp, nfhp, fhlen, NULL, NULL,
916 0, 0, NULL);
917 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
918 *tl++ = op->nfso_stateid.seqid;
919 *tl++ = op->nfso_stateid.other[0];
920 *tl++ = op->nfso_stateid.other[1];
921 *tl++ = op->nfso_stateid.other[2];
922 *tl = txdr_unsigned(op->nfso_own->nfsow_seqid);
923 error = nfscl_request(nd, vp, p, cred);
924 if (error)
925 return (error);
926 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
927 if (!nd->nd_repstat) {
928 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
929 op->nfso_stateid.seqid = *tl++;
930 op->nfso_stateid.other[0] = *tl++;
931 op->nfso_stateid.other[1] = *tl++;
932 op->nfso_stateid.other[2] = *tl;
933 }
934 error = nd->nd_repstat;
935 if (error == NFSERR_STALESTATEID)
936 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
937 nfsmout:
938 m_freem(nd->nd_mrep);
939 return (error);
940 }
941
942 /*
943 * Do the setclientid and setclientid confirm RPCs. Called from nfs_statfs()
944 * when a mount has just occurred and when the server replies NFSERR_EXPIRED.
945 */
946 int
947 nfsrpc_setclient(struct nfsmount *nmp, struct nfsclclient *clp, int reclaim,
948 bool *retokp, struct ucred *cred, NFSPROC_T *p)
949 {
950 u_int32_t *tl;
951 struct nfsrv_descript nfsd;
952 struct nfsrv_descript *nd = &nfsd;
953 u_int8_t *cp = NULL, *cp2, addr[INET6_ADDRSTRLEN + 9];
954 u_short port;
955 int error, isinet6 = 0, callblen;
956 nfsquad_t confirm;
957 static u_int32_t rev = 0;
958 struct nfsclds *dsp, *odsp;
959 struct in6_addr a6;
960 struct nfsclsession *tsep;
961 struct rpc_reconupcall recon;
962 struct nfscl_reconarg *rcp;
963
964 if (nfsboottime.tv_sec == 0)
965 NFSSETBOOTTIME(nfsboottime);
966 if (NFSHASNFSV4N(nmp)) {
967 error = NFSERR_BADSESSION;
968 odsp = dsp = NULL;
969 if (retokp != NULL) {
970 NFSLOCKMNT(nmp);
971 odsp = TAILQ_FIRST(&nmp->nm_sess);
972 NFSUNLOCKMNT(nmp);
973 }
974 if (odsp != NULL) {
975 /*
976 * When a session already exists, first try a
977 * CreateSession with the extant ClientID.
978 */
979 dsp = malloc(sizeof(struct nfsclds) +
980 odsp->nfsclds_servownlen + 1, M_NFSCLDS,
981 M_WAITOK | M_ZERO);
982 dsp->nfsclds_expire = NFSD_MONOSEC + clp->nfsc_renew;
983 dsp->nfsclds_servownlen = odsp->nfsclds_servownlen;
984 dsp->nfsclds_sess.nfsess_clientid =
985 odsp->nfsclds_sess.nfsess_clientid;
986 dsp->nfsclds_sess.nfsess_sequenceid =
987 odsp->nfsclds_sess.nfsess_sequenceid + 1;
988 dsp->nfsclds_flags = odsp->nfsclds_flags;
989 if (dsp->nfsclds_servownlen > 0)
990 memcpy(dsp->nfsclds_serverown,
991 odsp->nfsclds_serverown,
992 dsp->nfsclds_servownlen + 1);
993 mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF);
994 mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession",
995 NULL, MTX_DEF);
996 nfscl_initsessionslots(&dsp->nfsclds_sess);
997 error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess,
998 &nmp->nm_sockreq, NULL,
999 dsp->nfsclds_sess.nfsess_sequenceid, 1, cred, p);
1000 NFSCL_DEBUG(1, "create session for extant "
1001 "ClientID=%d\n", error);
1002 if (error != 0) {
1003 nfscl_freenfsclds(dsp);
1004 dsp = NULL;
1005 /*
1006 * If *retokp is true, return any error other
1007 * than NFSERR_STALECLIENTID,
1008 * NFSERR_BADSESSION or NFSERR_STALEDONTRECOVER
1009 * so that nfscl_recover() will not loop.
1010 */
1011 if (*retokp)
1012 return (NFSERR_IO);
1013 } else
1014 *retokp = true;
1015 } else if (retokp != NULL && *retokp)
1016 return (NFSERR_IO);
1017 if (error != 0) {
1018 /*
1019 * Either there was no previous session or the
1020 * CreateSession attempt failed, so...
1021 * do an ExchangeID followed by the CreateSession.
1022 */
1023 clp->nfsc_rev = rev++;
1024 error = nfsrpc_exchangeid(nmp, clp, &nmp->nm_sockreq, 0,
1025 NFSV4EXCH_USEPNFSMDS | NFSV4EXCH_USENONPNFS, &dsp,
1026 cred, p);
1027 NFSCL_DEBUG(1, "aft exch=%d\n", error);
1028 if (error == 0)
1029 error = nfsrpc_createsession(nmp,
1030 &dsp->nfsclds_sess, &nmp->nm_sockreq, NULL,
1031 dsp->nfsclds_sess.nfsess_sequenceid, 1,
1032 cred, p);
1033 NFSCL_DEBUG(1, "aft createsess=%d\n", error);
1034 }
1035 if (error == 0) {
1036 /*
1037 * If the session supports a backchannel, set up
1038 * the BindConnectionToSession call in the krpc
1039 * so that it is done on a reconnection.
1040 */
1041 if (nfscl_enablecallb != 0 && nfs_numnfscbd > 0) {
1042 rcp = mem_alloc(sizeof(*rcp));
1043 rcp->minorvers = nmp->nm_minorvers;
1044 memcpy(rcp->sessionid,
1045 dsp->nfsclds_sess.nfsess_sessionid,
1046 NFSX_V4SESSIONID);
1047 recon.call = nfsrpc_bindconnsess;
1048 recon.arg = rcp;
1049 CLNT_CONTROL(nmp->nm_client, CLSET_RECONUPCALL,
1050 &recon);
1051 }
1052
1053 NFSLOCKMNT(nmp);
1054 /*
1055 * The old sessions cannot be safely free'd
1056 * here, since they may still be used by
1057 * in-progress RPCs.
1058 */
1059 tsep = NULL;
1060 if (TAILQ_FIRST(&nmp->nm_sess) != NULL) {
1061 /*
1062 * Mark the old session defunct. Needed
1063 * when called from nfscl_hasexpired().
1064 */
1065 tsep = NFSMNT_MDSSESSION(nmp);
1066 tsep->nfsess_defunct = 1;
1067 }
1068 TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp,
1069 nfsclds_list);
1070 /*
1071 * Wake up RPCs waiting for a slot on the
1072 * old session. These will then fail with
1073 * NFSERR_BADSESSION and be retried with the
1074 * new session by nfsv4_setsequence().
1075 * Also wakeup() processes waiting for the
1076 * new session.
1077 */
1078 if (tsep != NULL)
1079 wakeup(&tsep->nfsess_slots);
1080 wakeup(&nmp->nm_sess);
1081 NFSUNLOCKMNT(nmp);
1082 } else if (dsp != NULL)
1083 nfscl_freenfsclds(dsp);
1084 if (error == 0 && reclaim == 0) {
1085 error = nfsrpc_reclaimcomplete(nmp, cred, p);
1086 NFSCL_DEBUG(1, "aft reclaimcomp=%d\n", error);
1087 if (error == NFSERR_COMPLETEALREADY ||
1088 error == NFSERR_NOTSUPP)
1089 /* Ignore this error. */
1090 error = 0;
1091 }
1092 return (error);
1093 } else if (retokp != NULL && *retokp)
1094 return (NFSERR_IO);
1095 clp->nfsc_rev = rev++;
1096
1097 /*
1098 * Allocate a single session structure for NFSv4.0, because some of
1099 * the fields are used by NFSv4.0 although it doesn't do a session.
1100 */
1101 dsp = malloc(sizeof(struct nfsclds), M_NFSCLDS, M_WAITOK | M_ZERO);
1102 mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF);
1103 mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", NULL, MTX_DEF);
1104 NFSLOCKMNT(nmp);
1105 TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp, nfsclds_list);
1106 tsep = NFSMNT_MDSSESSION(nmp);
1107 NFSUNLOCKMNT(nmp);
1108
1109 nfscl_reqstart(nd, NFSPROC_SETCLIENTID, nmp, NULL, 0, NULL, NULL, 0, 0,
1110 NULL);
1111 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1112 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
1113 *tl = txdr_unsigned(clp->nfsc_rev);
1114 (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen);
1115
1116 /*
1117 * set up the callback address
1118 */
1119 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1120 *tl = txdr_unsigned(NFS_CALLBCKPROG);
1121 callblen = strlen(nfsv4_callbackaddr);
1122 if (callblen == 0)
1123 cp = nfscl_getmyip(nmp, &a6, &isinet6);
1124 if (nfscl_enablecallb && nfs_numnfscbd > 0 &&
1125 (callblen > 0 || cp != NULL)) {
1126 port = htons(nfsv4_cbport);
1127 cp2 = (u_int8_t *)&port;
1128 #ifdef INET6
1129 if ((callblen > 0 &&
1130 strchr(nfsv4_callbackaddr, ':')) || isinet6) {
1131 char ip6buf[INET6_ADDRSTRLEN], *ip6add;
1132
1133 (void) nfsm_strtom(nd, "tcp6", 4);
1134 if (callblen == 0) {
1135 ip6_sprintf(ip6buf, (struct in6_addr *)cp);
1136 ip6add = ip6buf;
1137 } else {
1138 ip6add = nfsv4_callbackaddr;
1139 }
1140 snprintf(addr, INET6_ADDRSTRLEN + 9, "%s.%d.%d",
1141 ip6add, cp2[0], cp2[1]);
1142 } else
1143 #endif
1144 {
1145 (void) nfsm_strtom(nd, "tcp", 3);
1146 if (callblen == 0)
1147 snprintf(addr, INET6_ADDRSTRLEN + 9,
1148 "%d.%d.%d.%d.%d.%d", cp[0], cp[1],
1149 cp[2], cp[3], cp2[0], cp2[1]);
1150 else
1151 snprintf(addr, INET6_ADDRSTRLEN + 9,
1152 "%s.%d.%d", nfsv4_callbackaddr,
1153 cp2[0], cp2[1]);
1154 }
1155 (void) nfsm_strtom(nd, addr, strlen(addr));
1156 } else {
1157 (void) nfsm_strtom(nd, "tcp", 3);
1158 (void) nfsm_strtom(nd, "0.0.0.0.0.0", 11);
1159 }
1160 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1161 *tl = txdr_unsigned(clp->nfsc_cbident);
1162 nd->nd_flag |= ND_USEGSSNAME;
1163 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
1164 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
1165 if (error)
1166 return (error);
1167 if (nd->nd_repstat == 0) {
1168 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1169 tsep->nfsess_clientid.lval[0] = *tl++;
1170 tsep->nfsess_clientid.lval[1] = *tl++;
1171 confirm.lval[0] = *tl++;
1172 confirm.lval[1] = *tl;
1173 m_freem(nd->nd_mrep);
1174 nd->nd_mrep = NULL;
1175
1176 /*
1177 * and confirm it.
1178 */
1179 nfscl_reqstart(nd, NFSPROC_SETCLIENTIDCFRM, nmp, NULL, 0, NULL,
1180 NULL, 0, 0, NULL);
1181 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1182 *tl++ = tsep->nfsess_clientid.lval[0];
1183 *tl++ = tsep->nfsess_clientid.lval[1];
1184 *tl++ = confirm.lval[0];
1185 *tl = confirm.lval[1];
1186 nd->nd_flag |= ND_USEGSSNAME;
1187 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p,
1188 cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
1189 if (error)
1190 return (error);
1191 m_freem(nd->nd_mrep);
1192 nd->nd_mrep = NULL;
1193 }
1194 error = nd->nd_repstat;
1195 nfsmout:
1196 m_freem(nd->nd_mrep);
1197 return (error);
1198 }
1199
1200 /*
1201 * nfs getattr call.
1202 */
1203 int
1204 nfsrpc_getattr(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
1205 struct nfsvattr *nap)
1206 {
1207 struct nfsrv_descript nfsd, *nd = &nfsd;
1208 int error;
1209 nfsattrbit_t attrbits;
1210
1211 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp, cred);
1212 if (nd->nd_flag & ND_NFSV4) {
1213 NFSGETATTR_ATTRBIT(&attrbits);
1214 (void) nfsrv_putattrbit(nd, &attrbits);
1215 }
1216 error = nfscl_request(nd, vp, p, cred);
1217 if (error)
1218 return (error);
1219 if (!nd->nd_repstat)
1220 error = nfsm_loadattr(nd, nap);
1221 else
1222 error = nd->nd_repstat;
1223 m_freem(nd->nd_mrep);
1224 return (error);
1225 }
1226
1227 /*
1228 * nfs getattr call with non-vnode arguments.
1229 */
1230 int
1231 nfsrpc_getattrnovp(struct nfsmount *nmp, u_int8_t *fhp, int fhlen, int syscred,
1232 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, u_int64_t *xidp,
1233 uint32_t *leasep)
1234 {
1235 struct nfsrv_descript nfsd, *nd = &nfsd;
1236 int error, vers = NFS_VER2;
1237 nfsattrbit_t attrbits;
1238
1239 nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, fhp, fhlen, NULL, NULL, 0, 0,
1240 cred);
1241 if (nd->nd_flag & ND_NFSV4) {
1242 vers = NFS_VER4;
1243 NFSGETATTR_ATTRBIT(&attrbits);
1244 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME);
1245 (void) nfsrv_putattrbit(nd, &attrbits);
1246 } else if (nd->nd_flag & ND_NFSV3) {
1247 vers = NFS_VER3;
1248 }
1249 if (syscred)
1250 nd->nd_flag |= ND_USEGSSNAME;
1251 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
1252 NFS_PROG, vers, NULL, 1, xidp, NULL);
1253 if (error)
1254 return (error);
1255 if (nd->nd_repstat == 0) {
1256 if ((nd->nd_flag & ND_NFSV4) != 0)
1257 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
1258 NULL, NULL, NULL, NULL, NULL, 0, NULL, leasep, NULL,
1259 NULL, NULL);
1260 else
1261 error = nfsm_loadattr(nd, nap);
1262 } else
1263 error = nd->nd_repstat;
1264 m_freem(nd->nd_mrep);
1265 return (error);
1266 }
1267
1268 /*
1269 * Do an nfs setattr operation.
1270 */
1271 int
1272 nfsrpc_setattr(vnode_t vp, struct vattr *vap, NFSACL_T *aclp,
1273 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *rnap, int *attrflagp)
1274 {
1275 int error, expireret = 0, openerr, retrycnt;
1276 u_int32_t clidrev = 0, mode;
1277 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1278 struct nfsfh *nfhp;
1279 nfsv4stateid_t stateid;
1280 void *lckp;
1281
1282 if (nmp->nm_clp != NULL)
1283 clidrev = nmp->nm_clp->nfsc_clientidrev;
1284 if (vap != NULL && NFSATTRISSET(u_quad_t, vap, va_size))
1285 mode = NFSV4OPEN_ACCESSWRITE;
1286 else
1287 mode = NFSV4OPEN_ACCESSREAD;
1288 retrycnt = 0;
1289 do {
1290 lckp = NULL;
1291 openerr = 1;
1292 if (NFSHASNFSV4(nmp)) {
1293 nfhp = VTONFS(vp)->n_fhp;
1294 error = nfscl_getstateid(vp, nfhp->nfh_fh,
1295 nfhp->nfh_len, mode, 0, cred, p, &stateid, &lckp);
1296 if (error && vp->v_type == VREG &&
1297 (mode == NFSV4OPEN_ACCESSWRITE ||
1298 nfstest_openallsetattr)) {
1299 /*
1300 * No Open stateid, so try and open the file
1301 * now.
1302 */
1303 if (mode == NFSV4OPEN_ACCESSWRITE)
1304 openerr = nfsrpc_open(vp, FWRITE, cred,
1305 p);
1306 else
1307 openerr = nfsrpc_open(vp, FREAD, cred,
1308 p);
1309 if (!openerr)
1310 (void) nfscl_getstateid(vp,
1311 nfhp->nfh_fh, nfhp->nfh_len,
1312 mode, 0, cred, p, &stateid, &lckp);
1313 }
1314 }
1315 if (vap != NULL)
1316 error = nfsrpc_setattrrpc(vp, vap, &stateid, cred, p,
1317 rnap, attrflagp);
1318 else
1319 error = nfsrpc_setaclrpc(vp, cred, p, aclp, &stateid);
1320 if (error == NFSERR_OPENMODE && mode == NFSV4OPEN_ACCESSREAD) {
1321 NFSLOCKMNT(nmp);
1322 nmp->nm_state |= NFSSTA_OPENMODE;
1323 NFSUNLOCKMNT(nmp);
1324 }
1325 if (error == NFSERR_STALESTATEID)
1326 nfscl_initiate_recovery(nmp->nm_clp);
1327 if (lckp != NULL)
1328 nfscl_lockderef(lckp);
1329 if (!openerr)
1330 (void) nfsrpc_close(vp, 0, p);
1331 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1332 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1333 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
1334 (void) nfs_catnap(PZERO, error, "nfs_setattr");
1335 } else if ((error == NFSERR_EXPIRED ||
1336 ((!NFSHASINT(nmp) || !NFSHASNFSV4N(nmp)) &&
1337 error == NFSERR_BADSTATEID)) && clidrev != 0) {
1338 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1339 } else if (error == NFSERR_BADSTATEID && NFSHASINT(nmp) &&
1340 NFSHASNFSV4N(nmp)) {
1341 error = EIO;
1342 }
1343 retrycnt++;
1344 } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1345 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1346 error == NFSERR_BADSESSION ||
1347 (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
1348 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1349 expireret == 0 && clidrev != 0 && retrycnt < 4) ||
1350 (error == NFSERR_OPENMODE && mode == NFSV4OPEN_ACCESSREAD &&
1351 retrycnt < 4));
1352 if (error && retrycnt >= 4)
1353 error = EIO;
1354 return (error);
1355 }
1356
1357 static int
1358 nfsrpc_setattrrpc(vnode_t vp, struct vattr *vap,
1359 nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p,
1360 struct nfsvattr *rnap, int *attrflagp)
1361 {
1362 u_int32_t *tl;
1363 struct nfsrv_descript nfsd, *nd = &nfsd;
1364 int error;
1365 nfsattrbit_t attrbits;
1366
1367 *attrflagp = 0;
1368 NFSCL_REQSTART(nd, NFSPROC_SETATTR, vp, cred);
1369 if (nd->nd_flag & ND_NFSV4)
1370 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
1371 vap->va_type = vp->v_type;
1372 nfscl_fillsattr(nd, vap, vp, NFSSATTR_FULL, 0);
1373 if (nd->nd_flag & ND_NFSV3) {
1374 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1375 *tl = newnfs_false;
1376 } else if (nd->nd_flag & ND_NFSV4) {
1377 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1378 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1379 NFSGETATTR_ATTRBIT(&attrbits);
1380 (void) nfsrv_putattrbit(nd, &attrbits);
1381 }
1382 error = nfscl_request(nd, vp, p, cred);
1383 if (error)
1384 return (error);
1385 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
1386 error = nfscl_wcc_data(nd, vp, rnap, attrflagp, NULL, NULL);
1387 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 && !error)
1388 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1389 if (!(nd->nd_flag & ND_NFSV3) && !nd->nd_repstat && !error)
1390 error = nfscl_postop_attr(nd, rnap, attrflagp);
1391 m_freem(nd->nd_mrep);
1392 if (nd->nd_repstat && !error)
1393 error = nd->nd_repstat;
1394 return (error);
1395 }
1396
1397 /*
1398 * nfs lookup rpc
1399 */
1400 int
1401 nfsrpc_lookup(vnode_t dvp, char *name, int len, struct ucred *cred,
1402 NFSPROC_T *p, struct nfsvattr *dnap, struct nfsvattr *nap,
1403 struct nfsfh **nfhpp, int *attrflagp, int *dattrflagp, uint32_t openmode)
1404 {
1405 uint32_t deleg, rflags, *tl;
1406 struct nfsrv_descript nfsd, *nd = &nfsd;
1407 struct nfsmount *nmp;
1408 struct nfsnode *np;
1409 struct nfsfh *nfhp;
1410 nfsattrbit_t attrbits;
1411 int error = 0, lookupp = 0, newone, ret, retop;
1412 uint8_t own[NFSV4CL_LOCKNAMELEN];
1413 struct nfsclopen *op;
1414 struct nfscldeleg *ndp;
1415 nfsv4stateid_t stateid;
1416
1417 *attrflagp = 0;
1418 *dattrflagp = 0;
1419 if (dvp->v_type != VDIR)
1420 return (ENOTDIR);
1421 nmp = VFSTONFS(dvp->v_mount);
1422 if (len > NFS_MAXNAMLEN)
1423 return (ENAMETOOLONG);
1424 if (NFSHASNFSV4(nmp) && len == 1 &&
1425 name[0] == '.') {
1426 /*
1427 * Just return the current dir's fh.
1428 */
1429 np = VTONFS(dvp);
1430 nfhp = malloc(sizeof (struct nfsfh) +
1431 np->n_fhp->nfh_len, M_NFSFH, M_WAITOK);
1432 nfhp->nfh_len = np->n_fhp->nfh_len;
1433 NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len);
1434 *nfhpp = nfhp;
1435 return (0);
1436 }
1437 if (NFSHASNFSV4(nmp) && len == 2 &&
1438 name[0] == '.' && name[1] == '.') {
1439 lookupp = 1;
1440 openmode = 0;
1441 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, dvp, cred);
1442 } else if (openmode != 0) {
1443 NFSCL_REQSTART(nd, NFSPROC_LOOKUPOPEN, dvp, cred);
1444 nfsm_strtom(nd, name, len);
1445 } else {
1446 NFSCL_REQSTART(nd, NFSPROC_LOOKUP, dvp, cred);
1447 (void) nfsm_strtom(nd, name, len);
1448 }
1449 if (nd->nd_flag & ND_NFSV4) {
1450 NFSGETATTR_ATTRBIT(&attrbits);
1451 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1452 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
1453 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1454 (void) nfsrv_putattrbit(nd, &attrbits);
1455 if (openmode != 0) {
1456 /* Test for a VREG file. */
1457 NFSZERO_ATTRBIT(&attrbits);
1458 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TYPE);
1459 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
1460 *tl = txdr_unsigned(NFSV4OP_VERIFY);
1461 nfsrv_putattrbit(nd, &attrbits);
1462 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
1463 *tl++ = txdr_unsigned(NFSX_UNSIGNED);
1464 *tl = vtonfsv34_type(VREG);
1465
1466 /* Attempt the Open for VREG. */
1467 nfscl_filllockowner(NULL, own, F_POSIX);
1468 NFSM_BUILD(tl, uint32_t *, 6 * NFSX_UNSIGNED);
1469 *tl++ = txdr_unsigned(NFSV4OP_OPEN);
1470 *tl++ = 0; /* seqid, ignored. */
1471 *tl++ = txdr_unsigned(openmode);
1472 *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE);
1473 *tl++ = 0; /* ClientID, ignored. */
1474 *tl = 0;
1475 nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN);
1476 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
1477 *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE);
1478 *tl = txdr_unsigned(NFSV4OPEN_CLAIMFH);
1479 }
1480 }
1481 error = nfscl_request(nd, dvp, p, cred);
1482 if (error)
1483 return (error);
1484 ndp = NULL;
1485 if (nd->nd_repstat) {
1486 /*
1487 * When an NFSv4 Lookupp returns ENOENT, it means that
1488 * the lookup is at the root of an fs, so return this dir.
1489 */
1490 if (nd->nd_repstat == NFSERR_NOENT && lookupp) {
1491 np = VTONFS(dvp);
1492 nfhp = malloc(sizeof (struct nfsfh) +
1493 np->n_fhp->nfh_len, M_NFSFH, M_WAITOK);
1494 nfhp->nfh_len = np->n_fhp->nfh_len;
1495 NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len);
1496 *nfhpp = nfhp;
1497 m_freem(nd->nd_mrep);
1498 return (0);
1499 }
1500 if (nd->nd_flag & ND_NFSV3)
1501 error = nfscl_postop_attr(nd, dnap, dattrflagp);
1502 else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
1503 ND_NFSV4) {
1504 /* Load the directory attributes. */
1505 error = nfsm_loadattr(nd, dnap);
1506 if (error != 0)
1507 goto nfsmout;
1508 *dattrflagp = 1;
1509 }
1510 /* Check Lookup operation reply status. */
1511 if (openmode != 0 && (nd->nd_flag & ND_NOMOREDATA) == 0) {
1512 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
1513 if (*++tl != 0)
1514 goto nfsmout;
1515 }
1516 /* Look for GetFH reply. */
1517 if (openmode != 0 && (nd->nd_flag & ND_NOMOREDATA) == 0) {
1518 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
1519 if (*++tl != 0)
1520 goto nfsmout;
1521 error = nfsm_getfh(nd, nfhpp);
1522 if (error)
1523 goto nfsmout;
1524 }
1525 /* Look for Getattr reply. */
1526 if (openmode != 0 && (nd->nd_flag & ND_NOMOREDATA) == 0) {
1527 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
1528 if (*++tl != 0)
1529 goto nfsmout;
1530 error = nfsm_loadattr(nd, nap);
1531 if (error == 0) {
1532 /*
1533 * We have now successfully completed the
1534 * lookup, so set nd_repstat to 0.
1535 */
1536 nd->nd_repstat = 0;
1537 *attrflagp = 1;
1538 }
1539 }
1540 goto nfsmout;
1541 }
1542 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
1543 /* Load the directory attributes. */
1544 error = nfsm_loadattr(nd, dnap);
1545 if (error != 0)
1546 goto nfsmout;
1547 *dattrflagp = 1;
1548 /* Skip over the Lookup and GetFH operation status values. */
1549 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1550 }
1551 error = nfsm_getfh(nd, nfhpp);
1552 if (error)
1553 goto nfsmout;
1554
1555 error = nfscl_postop_attr(nd, nap, attrflagp);
1556 if (openmode != 0 && error == 0) {
1557 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID +
1558 10 * NFSX_UNSIGNED);
1559 tl += 4; /* Skip over Verify+Open status. */
1560 stateid.seqid = *tl++;
1561 stateid.other[0] = *tl++;
1562 stateid.other[1] = *tl++;
1563 stateid.other[2] = *tl;
1564 rflags = fxdr_unsigned(uint32_t, *(tl + 6));
1565 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1566 if (error != 0)
1567 goto nfsmout;
1568 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
1569 deleg = fxdr_unsigned(uint32_t, *tl);
1570 if (deleg == NFSV4OPEN_DELEGATEREAD ||
1571 deleg == NFSV4OPEN_DELEGATEWRITE) {
1572 /*
1573 * Just need to fill in the fields used by
1574 * nfscl_trydelegreturn().
1575 * Mark the mount point as acquiring
1576 * delegations, so NFSPROC_LOOKUPOPEN will
1577 * no longer be done.
1578 */
1579 NFSLOCKMNT(nmp);
1580 nmp->nm_privflag |= NFSMNTP_DELEGISSUED;
1581 NFSUNLOCKMNT(nmp);
1582 ndp = malloc(sizeof(struct nfscldeleg) +
1583 (*nfhpp)->nfh_len, M_NFSCLDELEG, M_WAITOK);
1584 ndp->nfsdl_fhlen = (*nfhpp)->nfh_len;
1585 NFSBCOPY((*nfhpp)->nfh_fh, ndp->nfsdl_fh,
1586 ndp->nfsdl_fhlen);
1587 newnfs_copyincred(cred, &ndp->nfsdl_cred);
1588 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
1589 ndp->nfsdl_stateid.seqid = *tl++;
1590 ndp->nfsdl_stateid.other[0] = *tl++;
1591 ndp->nfsdl_stateid.other[1] = *tl++;
1592 ndp->nfsdl_stateid.other[2] = *tl++;
1593 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
1594 error = NFSERR_BADXDR;
1595 goto nfsmout;
1596 }
1597 ret = nfscl_open(dvp, (*nfhpp)->nfh_fh, (*nfhpp)->nfh_len,
1598 openmode, 0, cred, p, NULL, &op, &newone, &retop, 1, true);
1599 if (ret != 0)
1600 goto nfsmout;
1601 if (newone != 0) {
1602 op->nfso_stateid.seqid = stateid.seqid;
1603 op->nfso_stateid.other[0] = stateid.other[0];
1604 op->nfso_stateid.other[1] = stateid.other[1];
1605 op->nfso_stateid.other[2] = stateid.other[2];
1606 op->nfso_mode = openmode;
1607 } else {
1608 op->nfso_stateid.seqid = stateid.seqid;
1609 if (retop == NFSCLOPEN_DOOPEN)
1610 op->nfso_mode |= openmode;
1611 }
1612 if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) != 0 ||
1613 nfscl_assumeposixlocks)
1614 op->nfso_posixlock = 1;
1615 else
1616 op->nfso_posixlock = 0;
1617 nfscl_openrelease(nmp, op, 0, 0);
1618 if (ndp != NULL) {
1619 /*
1620 * Since we do not have the vnode, we
1621 * cannot invalidate cached attributes.
1622 * Just return the delegation.
1623 */
1624 nfscl_trydelegreturn(ndp, cred, nmp, p);
1625 }
1626 }
1627 if ((nd->nd_flag & ND_NFSV3) && !error)
1628 error = nfscl_postop_attr(nd, dnap, dattrflagp);
1629 nfsmout:
1630 m_freem(nd->nd_mrep);
1631 if (!error && nd->nd_repstat)
1632 error = nd->nd_repstat;
1633 free(ndp, M_NFSCLDELEG);
1634 return (error);
1635 }
1636
1637 /*
1638 * Do a readlink rpc.
1639 */
1640 int
1641 nfsrpc_readlink(vnode_t vp, struct uio *uiop, struct ucred *cred,
1642 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp)
1643 {
1644 u_int32_t *tl;
1645 struct nfsrv_descript nfsd, *nd = &nfsd;
1646 struct nfsnode *np = VTONFS(vp);
1647 nfsattrbit_t attrbits;
1648 int error, len, cangetattr = 1;
1649
1650 *attrflagp = 0;
1651 NFSCL_REQSTART(nd, NFSPROC_READLINK, vp, cred);
1652 if (nd->nd_flag & ND_NFSV4) {
1653 /*
1654 * And do a Getattr op.
1655 */
1656 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1657 *tl = txdr_unsigned(NFSV4OP_GETATTR);
1658 NFSGETATTR_ATTRBIT(&attrbits);
1659 (void) nfsrv_putattrbit(nd, &attrbits);
1660 }
1661 error = nfscl_request(nd, vp, p, cred);
1662 if (error)
1663 return (error);
1664 if (nd->nd_flag & ND_NFSV3)
1665 error = nfscl_postop_attr(nd, nap, attrflagp);
1666 if (!nd->nd_repstat && !error) {
1667 NFSM_STRSIZ(len, NFS_MAXPATHLEN);
1668 /*
1669 * This seems weird to me, but must have been added to
1670 * FreeBSD for some reason. The only thing I can think of
1671 * is that there was/is some server that replies with
1672 * more link data than it should?
1673 */
1674 if (len == NFS_MAXPATHLEN) {
1675 NFSLOCKNODE(np);
1676 if (np->n_size > 0 && np->n_size < NFS_MAXPATHLEN) {
1677 len = np->n_size;
1678 cangetattr = 0;
1679 }
1680 NFSUNLOCKNODE(np);
1681 }
1682 error = nfsm_mbufuio(nd, uiop, len);
1683 if ((nd->nd_flag & ND_NFSV4) && !error && cangetattr)
1684 error = nfscl_postop_attr(nd, nap, attrflagp);
1685 }
1686 if (nd->nd_repstat && !error)
1687 error = nd->nd_repstat;
1688 nfsmout:
1689 m_freem(nd->nd_mrep);
1690 return (error);
1691 }
1692
1693 /*
1694 * Read operation.
1695 */
1696 int
1697 nfsrpc_read(vnode_t vp, struct uio *uiop, struct ucred *cred,
1698 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp)
1699 {
1700 int error, expireret = 0, retrycnt;
1701 u_int32_t clidrev = 0;
1702 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1703 struct nfsnode *np = VTONFS(vp);
1704 struct ucred *newcred;
1705 struct nfsfh *nfhp = NULL;
1706 nfsv4stateid_t stateid;
1707 void *lckp;
1708
1709 if (nmp->nm_clp != NULL)
1710 clidrev = nmp->nm_clp->nfsc_clientidrev;
1711 newcred = cred;
1712 if (NFSHASNFSV4(nmp)) {
1713 nfhp = np->n_fhp;
1714 newcred = NFSNEWCRED(cred);
1715 }
1716 retrycnt = 0;
1717 do {
1718 lckp = NULL;
1719 if (NFSHASNFSV4(nmp))
1720 (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
1721 NFSV4OPEN_ACCESSREAD, 0, newcred, p, &stateid,
1722 &lckp);
1723 error = nfsrpc_readrpc(vp, uiop, newcred, &stateid, p, nap,
1724 attrflagp);
1725 if (error == NFSERR_OPENMODE) {
1726 NFSLOCKMNT(nmp);
1727 nmp->nm_state |= NFSSTA_OPENMODE;
1728 NFSUNLOCKMNT(nmp);
1729 }
1730 if (error == NFSERR_STALESTATEID)
1731 nfscl_initiate_recovery(nmp->nm_clp);
1732 if (lckp != NULL)
1733 nfscl_lockderef(lckp);
1734 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1735 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1736 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
1737 (void) nfs_catnap(PZERO, error, "nfs_read");
1738 } else if ((error == NFSERR_EXPIRED ||
1739 ((!NFSHASINT(nmp) || !NFSHASNFSV4N(nmp)) &&
1740 error == NFSERR_BADSTATEID)) && clidrev != 0) {
1741 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1742 } else if (error == NFSERR_BADSTATEID && NFSHASINT(nmp) &&
1743 NFSHASNFSV4N(nmp)) {
1744 error = EIO;
1745 }
1746 retrycnt++;
1747 } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1748 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1749 error == NFSERR_BADSESSION ||
1750 (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
1751 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1752 expireret == 0 && clidrev != 0 && retrycnt < 4) ||
1753 (error == NFSERR_OPENMODE && retrycnt < 4));
1754 if (error && retrycnt >= 4)
1755 error = EIO;
1756 if (NFSHASNFSV4(nmp))
1757 NFSFREECRED(newcred);
1758 return (error);
1759 }
1760
1761 /*
1762 * The actual read RPC.
1763 */
1764 static int
1765 nfsrpc_readrpc(vnode_t vp, struct uio *uiop, struct ucred *cred,
1766 nfsv4stateid_t *stateidp, NFSPROC_T *p, struct nfsvattr *nap,
1767 int *attrflagp)
1768 {
1769 u_int32_t *tl;
1770 int error = 0, len, retlen, tsiz, eof = 0;
1771 struct nfsrv_descript nfsd;
1772 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1773 struct nfsrv_descript *nd = &nfsd;
1774 int rsize;
1775 off_t tmp_off;
1776
1777 *attrflagp = 0;
1778 tsiz = uiop->uio_resid;
1779 tmp_off = uiop->uio_offset + tsiz;
1780 NFSLOCKMNT(nmp);
1781 if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) {
1782 NFSUNLOCKMNT(nmp);
1783 return (EFBIG);
1784 }
1785 rsize = nmp->nm_rsize;
1786 NFSUNLOCKMNT(nmp);
1787 nd->nd_mrep = NULL;
1788 while (tsiz > 0) {
1789 *attrflagp = 0;
1790 len = (tsiz > rsize) ? rsize : tsiz;
1791 NFSCL_REQSTART(nd, NFSPROC_READ, vp, cred);
1792 if (nd->nd_flag & ND_NFSV4)
1793 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
1794 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED * 3);
1795 if (nd->nd_flag & ND_NFSV2) {
1796 *tl++ = txdr_unsigned(uiop->uio_offset);
1797 *tl++ = txdr_unsigned(len);
1798 *tl = 0;
1799 } else {
1800 txdr_hyper(uiop->uio_offset, tl);
1801 *(tl + 2) = txdr_unsigned(len);
1802 }
1803 /*
1804 * Since I can't do a Getattr for NFSv4 for Write, there
1805 * doesn't seem any point in doing one here, either.
1806 * (See the comment in nfsrpc_writerpc() for more info.)
1807 */
1808 error = nfscl_request(nd, vp, p, cred);
1809 if (error)
1810 return (error);
1811 if (nd->nd_flag & ND_NFSV3) {
1812 error = nfscl_postop_attr(nd, nap, attrflagp);
1813 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
1814 error = nfsm_loadattr(nd, nap);
1815 if (!error)
1816 *attrflagp = 1;
1817 }
1818 if (nd->nd_repstat || error) {
1819 if (!error)
1820 error = nd->nd_repstat;
1821 goto nfsmout;
1822 }
1823 if (nd->nd_flag & ND_NFSV3) {
1824 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1825 eof = fxdr_unsigned(int, *(tl + 1));
1826 } else if (nd->nd_flag & ND_NFSV4) {
1827 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1828 eof = fxdr_unsigned(int, *tl);
1829 }
1830 NFSM_STRSIZ(retlen, len);
1831 error = nfsm_mbufuio(nd, uiop, retlen);
1832 if (error)
1833 goto nfsmout;
1834 m_freem(nd->nd_mrep);
1835 nd->nd_mrep = NULL;
1836 tsiz -= retlen;
1837 if (!(nd->nd_flag & ND_NFSV2)) {
1838 if (eof || retlen == 0)
1839 tsiz = 0;
1840 } else if (retlen < len)
1841 tsiz = 0;
1842 }
1843 return (0);
1844 nfsmout:
1845 if (nd->nd_mrep != NULL)
1846 m_freem(nd->nd_mrep);
1847 return (error);
1848 }
1849
1850 /*
1851 * nfs write operation
1852 * When called_from_strategy != 0, it should return EIO for an error that
1853 * indicates recovery is in progress, so that the buffer will be left
1854 * dirty and be written back to the server later. If it loops around,
1855 * the recovery thread could get stuck waiting for the buffer and recovery
1856 * will then deadlock.
1857 */
1858 int
1859 nfsrpc_write(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
1860 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
1861 int called_from_strategy, int ioflag)
1862 {
1863 int error, expireret = 0, retrycnt, nostateid;
1864 u_int32_t clidrev = 0;
1865 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1866 struct nfsnode *np = VTONFS(vp);
1867 struct ucred *newcred;
1868 struct nfsfh *nfhp = NULL;
1869 nfsv4stateid_t stateid;
1870 void *lckp;
1871
1872 KASSERT(*must_commit >= 0 && *must_commit <= 2,
1873 ("nfsrpc_write: must_commit out of range=%d", *must_commit));
1874 if (nmp->nm_clp != NULL)
1875 clidrev = nmp->nm_clp->nfsc_clientidrev;
1876 newcred = cred;
1877 if (NFSHASNFSV4(nmp)) {
1878 newcred = NFSNEWCRED(cred);
1879 nfhp = np->n_fhp;
1880 }
1881 retrycnt = 0;
1882 do {
1883 lckp = NULL;
1884 nostateid = 0;
1885 if (NFSHASNFSV4(nmp)) {
1886 (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
1887 NFSV4OPEN_ACCESSWRITE, 0, newcred, p, &stateid,
1888 &lckp);
1889 if (stateid.other[0] == 0 && stateid.other[1] == 0 &&
1890 stateid.other[2] == 0) {
1891 nostateid = 1;
1892 NFSCL_DEBUG(1, "stateid0 in write\n");
1893 }
1894 }
1895
1896 /*
1897 * If there is no stateid for NFSv4, it means this is an
1898 * extraneous write after close. Basically a poorly
1899 * implemented buffer cache. Just don't do the write.
1900 */
1901 if (nostateid)
1902 error = 0;
1903 else
1904 error = nfsrpc_writerpc(vp, uiop, iomode, must_commit,
1905 newcred, &stateid, p, nap, attrflagp, ioflag);
1906 if (error == NFSERR_STALESTATEID)
1907 nfscl_initiate_recovery(nmp->nm_clp);
1908 if (lckp != NULL)
1909 nfscl_lockderef(lckp);
1910 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1911 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1912 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
1913 (void) nfs_catnap(PZERO, error, "nfs_write");
1914 } else if ((error == NFSERR_EXPIRED ||
1915 ((!NFSHASINT(nmp) || !NFSHASNFSV4N(nmp)) &&
1916 error == NFSERR_BADSTATEID)) && clidrev != 0) {
1917 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1918 } else if (error == NFSERR_BADSTATEID && NFSHASINT(nmp) &&
1919 NFSHASNFSV4N(nmp)) {
1920 error = EIO;
1921 }
1922 retrycnt++;
1923 } while (error == NFSERR_GRACE || error == NFSERR_DELAY ||
1924 ((error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION ||
1925 error == NFSERR_STALEDONTRECOVER) && called_from_strategy == 0) ||
1926 (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
1927 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1928 expireret == 0 && clidrev != 0 && retrycnt < 4));
1929 if (error != 0 && (retrycnt >= 4 ||
1930 ((error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION ||
1931 error == NFSERR_STALEDONTRECOVER) && called_from_strategy != 0)))
1932 error = EIO;
1933 if (NFSHASNFSV4(nmp))
1934 NFSFREECRED(newcred);
1935 return (error);
1936 }
1937
1938 /*
1939 * The actual write RPC.
1940 */
1941 static int
1942 nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode,
1943 int *must_commit, struct ucred *cred, nfsv4stateid_t *stateidp,
1944 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, int ioflag)
1945 {
1946 u_int32_t *tl;
1947 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1948 struct nfsnode *np = VTONFS(vp);
1949 int error = 0, len, rlen, commit, committed = NFSWRITE_FILESYNC;
1950 int wccflag = 0;
1951 int32_t backup;
1952 struct nfsrv_descript *nd;
1953 nfsattrbit_t attrbits;
1954 uint64_t tmp_off;
1955 ssize_t tsiz, wsize;
1956 bool do_append;
1957
1958 KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1"));
1959 *attrflagp = 0;
1960 tsiz = uiop->uio_resid;
1961 tmp_off = uiop->uio_offset + tsiz;
1962 NFSLOCKMNT(nmp);
1963 if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) {
1964 NFSUNLOCKMNT(nmp);
1965 return (EFBIG);
1966 }
1967 wsize = nmp->nm_wsize;
1968 do_append = false;
1969 if ((ioflag & IO_APPEND) != 0 && NFSHASNFSV4(nmp) && !NFSHASPNFS(nmp))
1970 do_append = true;
1971 NFSUNLOCKMNT(nmp);
1972 nd = malloc(sizeof(*nd), M_TEMP, M_WAITOK);
1973 nd->nd_mrep = NULL; /* NFSv2 sometimes does a write with */
1974 nd->nd_repstat = 0; /* uio_resid == 0, so the while is not done */
1975 while (tsiz > 0) {
1976 *attrflagp = 0;
1977 len = (tsiz > wsize) ? wsize : tsiz;
1978 if (do_append)
1979 NFSCL_REQSTART(nd, NFSPROC_APPENDWRITE, vp, cred);
1980 else
1981 NFSCL_REQSTART(nd, NFSPROC_WRITE, vp, cred);
1982 if (nd->nd_flag & ND_NFSV4) {
1983 if (do_append) {
1984 NFSZERO_ATTRBIT(&attrbits);
1985 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE);
1986 nfsrv_putattrbit(nd, &attrbits);
1987 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED +
1988 NFSX_HYPER);
1989 *tl++ = txdr_unsigned(NFSX_HYPER);
1990 txdr_hyper(uiop->uio_offset, tl); tl += 2;
1991 *tl = txdr_unsigned(NFSV4OP_WRITE);
1992 }
1993 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
1994 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+2*NFSX_UNSIGNED);
1995 txdr_hyper(uiop->uio_offset, tl);
1996 tl += 2;
1997 *tl++ = txdr_unsigned(*iomode);
1998 *tl = txdr_unsigned(len);
1999 } else if (nd->nd_flag & ND_NFSV3) {
2000 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+3*NFSX_UNSIGNED);
2001 txdr_hyper(uiop->uio_offset, tl);
2002 tl += 2;
2003 *tl++ = txdr_unsigned(len);
2004 *tl++ = txdr_unsigned(*iomode);
2005 *tl = txdr_unsigned(len);
2006 } else {
2007 u_int32_t x;
2008
2009 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
2010 /*
2011 * Not sure why someone changed this, since the
2012 * RFC clearly states that "beginoffset" and
2013 * "totalcount" are ignored, but it wouldn't
2014 * surprise me if there's a busted server out there.
2015 */
2016 /* Set both "begin" and "current" to non-garbage. */
2017 x = txdr_unsigned((u_int32_t)uiop->uio_offset);
2018 *tl++ = x; /* "begin offset" */
2019 *tl++ = x; /* "current offset" */
2020 x = txdr_unsigned(len);
2021 *tl++ = x; /* total to this offset */
2022 *tl = x; /* size of this write */
2023 }
2024 nfsm_uiombuf(nd, uiop, len);
2025 /*
2026 * Although it is tempting to do a normal Getattr Op in the
2027 * NFSv4 compound, the result can be a nearly hung client
2028 * system if the Getattr asks for Owner and/or OwnerGroup.
2029 * It occurs when the client can't map either the Owner or
2030 * Owner_group name in the Getattr reply to a uid/gid. When
2031 * there is a cache miss, the kernel does an upcall to the
2032 * nfsuserd. Then, it can try and read the local /etc/passwd
2033 * or /etc/group file. It can then block in getnewbuf(),
2034 * waiting for dirty writes to be pushed to the NFS server.
2035 * The only reason this doesn't result in a complete
2036 * deadlock, is that the upcall times out and allows
2037 * the write to complete. However, progress is so slow
2038 * that it might just as well be deadlocked.
2039 * As such, we get the rest of the attributes, but not
2040 * Owner or Owner_group.
2041 * nb: nfscl_loadattrcache() needs to be told that these
2042 * partial attributes from a write rpc are being
2043 * passed in, via a argument flag.
2044 */
2045 if (nd->nd_flag & ND_NFSV4) {
2046 NFSWRITEGETATTR_ATTRBIT(&attrbits);
2047 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2048 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2049 (void) nfsrv_putattrbit(nd, &attrbits);
2050 }
2051 error = nfscl_request(nd, vp, p, cred);
2052 if (error) {
2053 free(nd, M_TEMP);
2054 return (error);
2055 }
2056 if (nd->nd_repstat) {
2057 /*
2058 * In case the rpc gets retried, roll
2059 * the uio fields changed by nfsm_uiombuf()
2060 * back.
2061 */
2062 uiop->uio_offset -= len;
2063 uiop->uio_resid += len;
2064 uiop->uio_iov->iov_base =
2065 (char *)uiop->uio_iov->iov_base - len;
2066 uiop->uio_iov->iov_len += len;
2067 }
2068 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
2069 error = nfscl_wcc_data(nd, vp, nap, attrflagp,
2070 &wccflag, &tmp_off);
2071 if (error)
2072 goto nfsmout;
2073 }
2074 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
2075 (ND_NFSV4 | ND_NOMOREDATA) &&
2076 nd->nd_repstat == NFSERR_NOTSAME && do_append) {
2077 /*
2078 * Verify of the file's size failed, so redo the
2079 * write using the file's size as returned in
2080 * the wcc attributes.
2081 */
2082 if (tmp_off + tsiz <= nmp->nm_maxfilesize) {
2083 do_append = false;
2084 uiop->uio_offset = tmp_off;
2085 m_freem(nd->nd_mrep);
2086 nd->nd_mrep = NULL;
2087 continue;
2088 } else
2089 nd->nd_repstat = EFBIG;
2090 }
2091 if (!nd->nd_repstat) {
2092 if (do_append) {
2093 /* Strip off the Write reply status. */
2094 do_append = false;
2095 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
2096 }
2097 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
2098 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED
2099 + NFSX_VERF);
2100 rlen = fxdr_unsigned(int, *tl++);
2101 if (rlen == 0) {
2102 error = NFSERR_IO;
2103 goto nfsmout;
2104 } else if (rlen < len) {
2105 backup = len - rlen;
2106 uiop->uio_iov->iov_base =
2107 (char *)uiop->uio_iov->iov_base -
2108 backup;
2109 uiop->uio_iov->iov_len += backup;
2110 uiop->uio_offset -= backup;
2111 uiop->uio_resid += backup;
2112 len = rlen;
2113 }
2114 commit = fxdr_unsigned(int, *tl++);
2115
2116 /*
2117 * Return the lowest commitment level
2118 * obtained by any of the RPCs.
2119 */
2120 if (committed == NFSWRITE_FILESYNC)
2121 committed = commit;
2122 else if (committed == NFSWRITE_DATASYNC &&
2123 commit == NFSWRITE_UNSTABLE)
2124 committed = commit;
2125 NFSLOCKMNT(nmp);
2126 if (!NFSHASWRITEVERF(nmp)) {
2127 NFSBCOPY((caddr_t)tl,
2128 (caddr_t)&nmp->nm_verf[0],
2129 NFSX_VERF);
2130 NFSSETWRITEVERF(nmp);
2131 } else if (NFSBCMP(tl, nmp->nm_verf,
2132 NFSX_VERF) && *must_commit != 2) {
2133 *must_commit = 1;
2134 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
2135 }
2136 NFSUNLOCKMNT(nmp);
2137 }
2138 if (nd->nd_flag & ND_NFSV4)
2139 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2140 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV4)) {
2141 error = nfsm_loadattr(nd, nap);
2142 if (!error)
2143 *attrflagp = NFS_LATTR_NOSHRINK;
2144 }
2145 } else {
2146 error = nd->nd_repstat;
2147 }
2148 if (error)
2149 goto nfsmout;
2150 NFSWRITERPC_SETTIME(wccflag, np, nap, (nd->nd_flag & ND_NFSV4));
2151 m_freem(nd->nd_mrep);
2152 nd->nd_mrep = NULL;
2153 tsiz -= len;
2154 }
2155 nfsmout:
2156 if (nd->nd_mrep != NULL)
2157 m_freem(nd->nd_mrep);
2158 *iomode = committed;
2159 if (nd->nd_repstat && !error)
2160 error = nd->nd_repstat;
2161 free(nd, M_TEMP);
2162 return (error);
2163 }
2164
2165 /*
2166 * Do an nfs deallocate operation.
2167 */
2168 int
2169 nfsrpc_deallocate(vnode_t vp, off_t offs, off_t len, struct nfsvattr *nap,
2170 int *attrflagp, struct ucred *cred, NFSPROC_T *p)
2171 {
2172 int error, expireret = 0, openerr, retrycnt;
2173 uint32_t clidrev = 0;
2174 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
2175 struct nfsfh *nfhp;
2176 nfsv4stateid_t stateid;
2177 void *lckp;
2178
2179 if (nmp->nm_clp != NULL)
2180 clidrev = nmp->nm_clp->nfsc_clientidrev;
2181 retrycnt = 0;
2182 do {
2183 lckp = NULL;
2184 openerr = 1;
2185 nfhp = VTONFS(vp)->n_fhp;
2186 error = nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
2187 NFSV4OPEN_ACCESSWRITE, 0, cred, p, &stateid, &lckp);
2188 if (error != 0) {
2189 /*
2190 * No Open stateid, so try and open the file
2191 * now.
2192 */
2193 openerr = nfsrpc_open(vp, FWRITE, cred, p);
2194 if (openerr == 0)
2195 nfscl_getstateid(vp, nfhp->nfh_fh,
2196 nfhp->nfh_len, NFSV4OPEN_ACCESSWRITE, 0,
2197 cred, p, &stateid, &lckp);
2198 }
2199 error = nfsrpc_deallocaterpc(vp, offs, len, &stateid, nap,
2200 attrflagp, cred, p);
2201 if (error == NFSERR_STALESTATEID)
2202 nfscl_initiate_recovery(nmp->nm_clp);
2203 if (lckp != NULL)
2204 nfscl_lockderef(lckp);
2205 if (openerr == 0)
2206 nfsrpc_close(vp, 0, p);
2207 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
2208 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
2209 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
2210 (void) nfs_catnap(PZERO, error, "nfs_deallocate");
2211 } else if ((error == NFSERR_EXPIRED || (!NFSHASINT(nmp) &&
2212 error == NFSERR_BADSTATEID)) && clidrev != 0) {
2213 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
2214 } else if (error == NFSERR_BADSTATEID && NFSHASINT(nmp)) {
2215 error = EIO;
2216 }
2217 retrycnt++;
2218 } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
2219 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
2220 error == NFSERR_BADSESSION ||
2221 (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
2222 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
2223 expireret == 0 && clidrev != 0 && retrycnt < 4));
2224 if (error && retrycnt >= 4)
2225 error = EIO;
2226 return (error);
2227 }
2228
2229 /*
2230 * The actual deallocate RPC.
2231 */
2232 static int
2233 nfsrpc_deallocaterpc(vnode_t vp, off_t offs, off_t len,
2234 nfsv4stateid_t *stateidp, struct nfsvattr *nap, int *attrflagp,
2235 struct ucred *cred, NFSPROC_T *p)
2236 {
2237 uint32_t *tl;
2238 struct nfsnode *np = VTONFS(vp);
2239 int error, wccflag;
2240 struct nfsrv_descript nfsd;
2241 struct nfsrv_descript *nd = &nfsd;
2242 nfsattrbit_t attrbits;
2243
2244 *attrflagp = 0;
2245 NFSCL_REQSTART(nd, NFSPROC_DEALLOCATE, vp, cred);
2246 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
2247 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER);
2248 txdr_hyper(offs, tl);
2249 tl += 2;
2250 txdr_hyper(len, tl);
2251 NFSWRITEGETATTR_ATTRBIT(&attrbits);
2252 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
2253 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2254 nfsrv_putattrbit(nd, &attrbits);
2255 error = nfscl_request(nd, vp, p, cred);
2256 if (error != 0)
2257 return (error);
2258 wccflag = 0;
2259 error = nfscl_wcc_data(nd, vp, nap, attrflagp, &wccflag, NULL);
2260 if (error != 0)
2261 goto nfsmout;
2262 if (nd->nd_repstat == 0) {
2263 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
2264 error = nfsm_loadattr(nd, nap);
2265 if (error != 0)
2266 goto nfsmout;
2267 *attrflagp = NFS_LATTR_NOSHRINK;
2268 }
2269 NFSWRITERPC_SETTIME(wccflag, np, nap, 1);
2270 nfsmout:
2271 m_freem(nd->nd_mrep);
2272 if (nd->nd_repstat != 0 && error == 0)
2273 error = nd->nd_repstat;
2274 return (error);
2275 }
2276
2277 /*
2278 * nfs mknod rpc
2279 * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the
2280 * mode set to specify the file type and the size field for rdev.
2281 */
2282 int
2283 nfsrpc_mknod(vnode_t dvp, char *name, int namelen, struct vattr *vap,
2284 u_int32_t rdev, enum vtype vtyp, struct ucred *cred, NFSPROC_T *p,
2285 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
2286 int *attrflagp, int *dattrflagp)
2287 {
2288 u_int32_t *tl;
2289 int error = 0;
2290 struct nfsrv_descript nfsd, *nd = &nfsd;
2291 nfsattrbit_t attrbits;
2292
2293 *nfhpp = NULL;
2294 *attrflagp = 0;
2295 *dattrflagp = 0;
2296 if (namelen > NFS_MAXNAMLEN)
2297 return (ENAMETOOLONG);
2298 NFSCL_REQSTART(nd, NFSPROC_MKNOD, dvp, cred);
2299 if (nd->nd_flag & ND_NFSV4) {
2300 if (vtyp == VBLK || vtyp == VCHR) {
2301 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2302 *tl++ = vtonfsv34_type(vtyp);
2303 *tl++ = txdr_unsigned(NFSMAJOR(rdev));
2304 *tl = txdr_unsigned(NFSMINOR(rdev));
2305 } else {
2306 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2307 *tl = vtonfsv34_type(vtyp);
2308 }
2309 }
2310 (void) nfsm_strtom(nd, name, namelen);
2311 if (nd->nd_flag & ND_NFSV3) {
2312 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2313 *tl = vtonfsv34_type(vtyp);
2314 }
2315 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
2316 nfscl_fillsattr(nd, vap, dvp, 0, 0);
2317 if ((nd->nd_flag & ND_NFSV3) &&
2318 (vtyp == VCHR || vtyp == VBLK)) {
2319 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2320 *tl++ = txdr_unsigned(NFSMAJOR(rdev));
2321 *tl = txdr_unsigned(NFSMINOR(rdev));
2322 }
2323 if (nd->nd_flag & ND_NFSV4) {
2324 NFSGETATTR_ATTRBIT(&attrbits);
2325 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2326 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
2327 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2328 (void) nfsrv_putattrbit(nd, &attrbits);
2329 }
2330 if (nd->nd_flag & ND_NFSV2)
2331 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZERDEV, rdev);
2332 error = nfscl_request(nd, dvp, p, cred);
2333 if (error)
2334 return (error);
2335 if (nd->nd_flag & ND_NFSV4)
2336 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL);
2337 if (!nd->nd_repstat) {
2338 if (nd->nd_flag & ND_NFSV4) {
2339 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2340 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
2341 if (error)
2342 goto nfsmout;
2343 }
2344 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
2345 if (error)
2346 goto nfsmout;
2347 }
2348 if (nd->nd_flag & ND_NFSV3)
2349 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL);
2350 if (!error && nd->nd_repstat)
2351 error = nd->nd_repstat;
2352 nfsmout:
2353 m_freem(nd->nd_mrep);
2354 return (error);
2355 }
2356
2357 /*
2358 * nfs file create call
2359 * Mostly just call the approriate routine. (I separated out v4, so that
2360 * error recovery wouldn't be as difficult.)
2361 */
2362 int
2363 nfsrpc_create(vnode_t dvp, char *name, int namelen, struct vattr *vap,
2364 nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p,
2365 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
2366 int *attrflagp, int *dattrflagp)
2367 {
2368 int error = 0, newone, expireret = 0, retrycnt, unlocked;
2369 struct nfsclowner *owp;
2370 struct nfscldeleg *dp;
2371 struct nfsmount *nmp = VFSTONFS(dvp->v_mount);
2372 u_int32_t clidrev;
2373
2374 if (NFSHASNFSV4(nmp)) {
2375 retrycnt = 0;
2376 do {
2377 dp = NULL;
2378 error = nfscl_open(dvp, NULL, 0, (NFSV4OPEN_ACCESSWRITE |
2379 NFSV4OPEN_ACCESSREAD), 0, cred, p, &owp, NULL, &newone,
2380 NULL, 1, true);
2381 if (error)
2382 return (error);
2383 if (nmp->nm_clp != NULL)
2384 clidrev = nmp->nm_clp->nfsc_clientidrev;
2385 else
2386 clidrev = 0;
2387 if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 ||
2388 nfs_numnfscbd == 0 || retrycnt > 0)
2389 error = nfsrpc_createv4(dvp, name, namelen, vap, cverf,
2390 fmode, owp, &dp, cred, p, dnap, nnap, nfhpp,
2391 attrflagp, dattrflagp, &unlocked);
2392 else
2393 error = nfsrpc_getcreatelayout(dvp, name, namelen, vap,
2394 cverf, fmode, owp, &dp, cred, p, dnap, nnap, nfhpp,
2395 attrflagp, dattrflagp, &unlocked);
2396 /*
2397 * There is no need to invalidate cached attributes here,
2398 * since new post-delegation issue attributes are always
2399 * returned by nfsrpc_createv4() and these will update the
2400 * attribute cache.
2401 */
2402 if (dp != NULL)
2403 (void) nfscl_deleg(nmp->nm_mountp, owp->nfsow_clp,
2404 (*nfhpp)->nfh_fh, (*nfhpp)->nfh_len, cred, p, &dp);
2405 nfscl_ownerrelease(nmp, owp, error, newone, unlocked);
2406 if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
2407 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
2408 error == NFSERR_BADSESSION) {
2409 (void) nfs_catnap(PZERO, error, "nfs_open");
2410 } else if ((error == NFSERR_EXPIRED ||
2411 error == NFSERR_BADSTATEID) && clidrev != 0) {
2412 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
2413 retrycnt++;
2414 }
2415 } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
2416 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
2417 error == NFSERR_BADSESSION ||
2418 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
2419 expireret == 0 && clidrev != 0 && retrycnt < 4));
2420 if (error && retrycnt >= 4)
2421 error = EIO;
2422 } else {
2423 error = nfsrpc_createv23(dvp, name, namelen, vap, cverf,
2424 fmode, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp);
2425 }
2426 return (error);
2427 }
2428
2429 /*
2430 * The create rpc for v2 and 3.
2431 */
2432 static int
2433 nfsrpc_createv23(vnode_t dvp, char *name, int namelen, struct vattr *vap,
2434 nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p,
2435 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
2436 int *attrflagp, int *dattrflagp)
2437 {
2438 u_int32_t *tl;
2439 int error = 0;
2440 struct nfsrv_descript nfsd, *nd = &nfsd;
2441
2442 *nfhpp = NULL;
2443 *attrflagp = 0;
2444 *dattrflagp = 0;
2445 if (namelen > NFS_MAXNAMLEN)
2446 return (ENAMETOOLONG);
2447 NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp, cred);
2448 (void) nfsm_strtom(nd, name, namelen);
2449 if (nd->nd_flag & ND_NFSV3) {
2450 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2451 if (fmode & O_EXCL) {
2452 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE);
2453 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2454 *tl++ = cverf.lval[0];
2455 *tl = cverf.lval[1];
2456 } else {
2457 *tl = txdr_unsigned(NFSCREATE_UNCHECKED);
2458 nfscl_fillsattr(nd, vap, dvp, 0, 0);
2459 }
2460 } else {
2461 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZE0, 0);
2462 }
2463 error = nfscl_request(nd, dvp, p, cred);
2464 if (error)
2465 return (error);
2466 if (nd->nd_repstat == 0) {
2467 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
2468 if (error)
2469 goto nfsmout;
2470 }
2471 if (nd->nd_flag & ND_NFSV3)
2472 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL);
2473 if (nd->nd_repstat != 0 && error == 0)
2474 error = nd->nd_repstat;
2475 nfsmout:
2476 m_freem(nd->nd_mrep);
2477 return (error);
2478 }
2479
2480 static int
2481 nfsrpc_createv4(vnode_t dvp, char *name, int namelen, struct vattr *vap,
2482 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp,
2483 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
2484 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
2485 int *dattrflagp, int *unlockedp)
2486 {
2487 u_int32_t *tl;
2488 int error = 0, deleg, newone, ret, acesize, limitby;
2489 struct nfsrv_descript nfsd, *nd = &nfsd;
2490 struct nfsclopen *op;
2491 struct nfscldeleg *dp = NULL;
2492 struct nfsnode *np;
2493 struct nfsfh *nfhp;
2494 nfsattrbit_t attrbits;
2495 nfsv4stateid_t stateid;
2496 u_int32_t rflags;
2497 struct nfsmount *nmp;
2498 struct nfsclsession *tsep;
2499
2500 nmp = VFSTONFS(dvp->v_mount);
2501 np = VTONFS(dvp);
2502 *unlockedp = 0;
2503 *nfhpp = NULL;
2504 *dpp = NULL;
2505 *attrflagp = 0;
2506 *dattrflagp = 0;
2507 if (namelen > NFS_MAXNAMLEN)
2508 return (ENAMETOOLONG);
2509 NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp, cred);
2510 /*
2511 * For V4, this is actually an Open op.
2512 */
2513 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2514 *tl++ = txdr_unsigned(owp->nfsow_seqid);
2515 *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
2516 NFSV4OPEN_ACCESSREAD);
2517 *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE);
2518 tsep = nfsmnt_mdssession(nmp);
2519 *tl++ = tsep->nfsess_clientid.lval[0];
2520 *tl = tsep->nfsess_clientid.lval[1];
2521 (void) nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN);
2522 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2523 *tl++ = txdr_unsigned(NFSV4OPEN_CREATE);
2524 if (fmode & O_EXCL) {
2525 if (NFSHASNFSV4N(nmp)) {
2526 if (NFSHASSESSPERSIST(nmp)) {
2527 /* Use GUARDED for persistent sessions. */
2528 *tl = txdr_unsigned(NFSCREATE_GUARDED);
2529 nfscl_fillsattr(nd, vap, dvp, 0, 0);
2530 } else {
2531 /* Otherwise, use EXCLUSIVE4_1. */
2532 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41);
2533 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2534 *tl++ = cverf.lval[0];
2535 *tl = cverf.lval[1];
2536 nfscl_fillsattr(nd, vap, dvp, 0, 0);
2537 }
2538 } else {
2539 /* NFSv4.0 */
2540 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE);
2541 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2542 *tl++ = cverf.lval[0];
2543 *tl = cverf.lval[1];
2544 }
2545 } else {
2546 *tl = txdr_unsigned(NFSCREATE_UNCHECKED);
2547 nfscl_fillsattr(nd, vap, dvp, 0, 0);
2548 }
2549 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2550 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
2551 (void) nfsm_strtom(nd, name, namelen);
2552 /* Get the new file's handle and attributes. */
2553 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2554 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
2555 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2556 NFSGETATTR_ATTRBIT(&attrbits);
2557 (void) nfsrv_putattrbit(nd, &attrbits);
2558 /* Get the directory's post-op attributes. */
2559 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2560 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2561 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0);
2562 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2563 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2564 (void) nfsrv_putattrbit(nd, &attrbits);
2565 error = nfscl_request(nd, dvp, p, cred);
2566 if (error)
2567 return (error);
2568 NFSCL_INCRSEQID(owp->nfsow_seqid, nd);
2569 if (nd->nd_repstat == 0) {
2570 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
2571 6 * NFSX_UNSIGNED);
2572 stateid.seqid = *tl++;
2573 stateid.other[0] = *tl++;
2574 stateid.other[1] = *tl++;
2575 stateid.other[2] = *tl;
2576 rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
2577 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
2578 if (error)
2579 goto nfsmout;
2580 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2581 deleg = fxdr_unsigned(int, *tl);
2582 if (deleg == NFSV4OPEN_DELEGATEREAD ||
2583 deleg == NFSV4OPEN_DELEGATEWRITE) {
2584 if (!(owp->nfsow_clp->nfsc_flags &
2585 NFSCLFLAGS_FIRSTDELEG))
2586 owp->nfsow_clp->nfsc_flags |=
2587 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
2588 dp = malloc(
2589 sizeof (struct nfscldeleg) + NFSX_V4FHMAX,
2590 M_NFSCLDELEG, M_WAITOK);
2591 LIST_INIT(&dp->nfsdl_owner);
2592 LIST_INIT(&dp->nfsdl_lock);
2593 dp->nfsdl_clp = owp->nfsow_clp;
2594 newnfs_copyincred(cred, &dp->nfsdl_cred);
2595 nfscl_lockinit(&dp->nfsdl_rwlock);
2596 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
2597 NFSX_UNSIGNED);
2598 dp->nfsdl_stateid.seqid = *tl++;
2599 dp->nfsdl_stateid.other[0] = *tl++;
2600 dp->nfsdl_stateid.other[1] = *tl++;
2601 dp->nfsdl_stateid.other[2] = *tl++;
2602 ret = fxdr_unsigned(int, *tl);
2603 if (deleg == NFSV4OPEN_DELEGATEWRITE) {
2604 dp->nfsdl_flags = NFSCLDL_WRITE;
2605 /*
2606 * Indicates how much the file can grow.
2607 */
2608 NFSM_DISSECT(tl, u_int32_t *,
2609 3 * NFSX_UNSIGNED);
2610 limitby = fxdr_unsigned(int, *tl++);
2611 switch (limitby) {
2612 case NFSV4OPEN_LIMITSIZE:
2613 dp->nfsdl_sizelimit = fxdr_hyper(tl);
2614 break;
2615 case NFSV4OPEN_LIMITBLOCKS:
2616 dp->nfsdl_sizelimit =
2617 fxdr_unsigned(u_int64_t, *tl++);
2618 dp->nfsdl_sizelimit *=
2619 fxdr_unsigned(u_int64_t, *tl);
2620 break;
2621 default:
2622 error = NFSERR_BADXDR;
2623 goto nfsmout;
2624 }
2625 } else {
2626 dp->nfsdl_flags = NFSCLDL_READ;
2627 }
2628 if (ret)
2629 dp->nfsdl_flags |= NFSCLDL_RECALL;
2630 error = nfsrv_dissectace(nd, &dp->nfsdl_ace, false,
2631 &ret, &acesize, p);
2632 if (error)
2633 goto nfsmout;
2634 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
2635 error = NFSERR_BADXDR;
2636 goto nfsmout;
2637 }
2638 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
2639 if (error)
2640 goto nfsmout;
2641 /* Get rid of the PutFH and Getattr status values. */
2642 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
2643 /* Load the directory attributes. */
2644 error = nfsm_loadattr(nd, dnap);
2645 if (error)
2646 goto nfsmout;
2647 *dattrflagp = 1;
2648 if (dp != NULL && *attrflagp) {
2649 dp->nfsdl_change = nnap->na_filerev;
2650 dp->nfsdl_modtime = nnap->na_mtime;
2651 dp->nfsdl_flags |= NFSCLDL_MODTIMESET;
2652 }
2653 /*
2654 * We can now complete the Open state.
2655 */
2656 nfhp = *nfhpp;
2657 if (dp != NULL) {
2658 dp->nfsdl_fhlen = nfhp->nfh_len;
2659 NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, nfhp->nfh_len);
2660 }
2661 /*
2662 * Get an Open structure that will be
2663 * attached to the OpenOwner, acquired already.
2664 */
2665 error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len,
2666 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0,
2667 cred, p, NULL, &op, &newone, NULL, 0, false);
2668 if (error)
2669 goto nfsmout;
2670 op->nfso_stateid = stateid;
2671 newnfs_copyincred(cred, &op->nfso_cred);
2672 if ((rflags & NFSV4OPEN_RESULTCONFIRM)) {
2673 do {
2674 ret = nfsrpc_openconfirm(dvp, nfhp->nfh_fh,
2675 nfhp->nfh_len, op, cred, p);
2676 if (ret == NFSERR_DELAY)
2677 (void) nfs_catnap(PZERO, ret, "nfs_create");
2678 } while (ret == NFSERR_DELAY);
2679 error = ret;
2680 }
2681
2682 /*
2683 * If the server is handing out delegations, but we didn't
2684 * get one because an OpenConfirm was required, try the
2685 * Open again, to get a delegation. This is a harmless no-op,
2686 * from a server's point of view.
2687 */
2688 if ((rflags & NFSV4OPEN_RESULTCONFIRM) &&
2689 (owp->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) &&
2690 !error && dp == NULL) {
2691 do {
2692 ret = nfsrpc_openrpc(VFSTONFS(dvp->v_mount), dvp,
2693 np->n_fhp->nfh_fh, np->n_fhp->nfh_len,
2694 nfhp->nfh_fh, nfhp->nfh_len,
2695 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), op,
2696 name, namelen, &dp, 0, 0x0, cred, p, 0, 1);
2697 if (ret == NFSERR_DELAY)
2698 (void) nfs_catnap(PZERO, ret, "nfs_crt2");
2699 } while (ret == NFSERR_DELAY);
2700 if (ret) {
2701 if (dp != NULL) {
2702 free(dp, M_NFSCLDELEG);
2703 dp = NULL;
2704 }
2705 if (ret == NFSERR_STALECLIENTID ||
2706 ret == NFSERR_STALEDONTRECOVER ||
2707 ret == NFSERR_BADSESSION)
2708 error = ret;
2709 }
2710 }
2711 nfscl_openrelease(nmp, op, error, newone);
2712 *unlockedp = 1;
2713 }
2714 if (nd->nd_repstat != 0 && error == 0)
2715 error = nd->nd_repstat;
2716 if (error == NFSERR_STALECLIENTID)
2717 nfscl_initiate_recovery(owp->nfsow_clp);
2718 nfsmout:
2719 if (!error)
2720 *dpp = dp;
2721 else if (dp != NULL)
2722 free(dp, M_NFSCLDELEG);
2723 m_freem(nd->nd_mrep);
2724 return (error);
2725 }
2726
2727 /*
2728 * Nfs remove rpc
2729 */
2730 int
2731 nfsrpc_remove(vnode_t dvp, char *name, int namelen, vnode_t vp,
2732 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp)
2733 {
2734 u_int32_t *tl;
2735 struct nfsrv_descript nfsd, *nd = &nfsd;
2736 struct nfsnode *np;
2737 struct nfsmount *nmp;
2738 nfsv4stateid_t dstateid;
2739 int error, ret = 0, i;
2740
2741 *dattrflagp = 0;
2742 if (namelen > NFS_MAXNAMLEN)
2743 return (ENAMETOOLONG);
2744 nmp = VFSTONFS(dvp->v_mount);
2745 tryagain:
2746 if (NFSHASNFSV4(nmp) && ret == 0) {
2747 ret = nfscl_removedeleg(vp, p, &dstateid);
2748 if (ret == 1) {
2749 NFSCL_REQSTART(nd, NFSPROC_RETDELEGREMOVE, vp, cred);
2750 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID +
2751 NFSX_UNSIGNED);
2752 if (NFSHASNFSV4N(nmp))
2753 *tl++ = 0;
2754 else
2755 *tl++ = dstateid.seqid;
2756 *tl++ = dstateid.other[0];
2757 *tl++ = dstateid.other[1];
2758 *tl++ = dstateid.other[2];
2759 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2760 np = VTONFS(dvp);
2761 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
2762 np->n_fhp->nfh_len, 0);
2763 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2764 *tl = txdr_unsigned(NFSV4OP_REMOVE);
2765 }
2766 } else {
2767 ret = 0;
2768 }
2769 if (ret == 0)
2770 NFSCL_REQSTART(nd, NFSPROC_REMOVE, dvp, cred);
2771 (void) nfsm_strtom(nd, name, namelen);
2772 error = nfscl_request(nd, dvp, p, cred);
2773 if (error)
2774 return (error);
2775 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
2776 /* For NFSv4, parse out any Delereturn replies. */
2777 if (ret > 0 && nd->nd_repstat != 0 &&
2778 (nd->nd_flag & ND_NOMOREDATA)) {
2779 /*
2780 * If the Delegreturn failed, try again without
2781 * it. The server will Recall, as required.
2782 */
2783 m_freem(nd->nd_mrep);
2784 goto tryagain;
2785 }
2786 for (i = 0; i < (ret * 2); i++) {
2787 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
2788 ND_NFSV4) {
2789 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2790 if (*(tl + 1))
2791 nd->nd_flag |= ND_NOMOREDATA;
2792 }
2793 }
2794 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL);
2795 }
2796 if (nd->nd_repstat && !error)
2797 error = nd->nd_repstat;
2798 nfsmout:
2799 m_freem(nd->nd_mrep);
2800 return (error);
2801 }
2802
2803 /*
2804 * Do an nfs rename rpc.
2805 */
2806 int
2807 nfsrpc_rename(vnode_t fdvp, vnode_t fvp, char *fnameptr, int fnamelen,
2808 vnode_t tdvp, vnode_t tvp, char *tnameptr, int tnamelen, struct ucred *cred,
2809 NFSPROC_T *p, struct nfsvattr *fnap, struct nfsvattr *tnap,
2810 int *fattrflagp, int *tattrflagp)
2811 {
2812 u_int32_t *tl;
2813 struct nfsrv_descript nfsd, *nd = &nfsd;
2814 struct nfsmount *nmp;
2815 struct nfsnode *np;
2816 nfsattrbit_t attrbits;
2817 nfsv4stateid_t fdstateid, tdstateid;
2818 int error = 0, ret = 0, gottd = 0, gotfd = 0, i;
2819
2820 *fattrflagp = 0;
2821 *tattrflagp = 0;
2822 nmp = VFSTONFS(fdvp->v_mount);
2823 if (fnamelen > NFS_MAXNAMLEN || tnamelen > NFS_MAXNAMLEN)
2824 return (ENAMETOOLONG);
2825 tryagain:
2826 if (NFSHASNFSV4(nmp) && ret == 0) {
2827 ret = nfscl_renamedeleg(fvp, &fdstateid, &gotfd, tvp,
2828 &tdstateid, &gottd, p);
2829 if (gotfd && gottd) {
2830 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME2, fvp, cred);
2831 } else if (gotfd) {
2832 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, fvp, cred);
2833 } else if (gottd) {
2834 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, tvp, cred);
2835 }
2836 if (gotfd) {
2837 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2838 if (NFSHASNFSV4N(nmp))
2839 *tl++ = 0;
2840 else
2841 *tl++ = fdstateid.seqid;
2842 *tl++ = fdstateid.other[0];
2843 *tl++ = fdstateid.other[1];
2844 *tl = fdstateid.other[2];
2845 if (gottd) {
2846 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2847 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2848 np = VTONFS(tvp);
2849 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
2850 np->n_fhp->nfh_len, 0);
2851 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2852 *tl = txdr_unsigned(NFSV4OP_DELEGRETURN);
2853 }
2854 }
2855 if (gottd) {
2856 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2857 if (NFSHASNFSV4N(nmp))
2858 *tl++ = 0;
2859 else
2860 *tl++ = tdstateid.seqid;
2861 *tl++ = tdstateid.other[0];
2862 *tl++ = tdstateid.other[1];
2863 *tl = tdstateid.other[2];
2864 }
2865 if (ret > 0) {
2866 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2867 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2868 np = VTONFS(fdvp);
2869 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
2870 np->n_fhp->nfh_len, 0);
2871 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2872 *tl = txdr_unsigned(NFSV4OP_SAVEFH);
2873 }
2874 } else {
2875 ret = 0;
2876 }
2877 if (ret == 0)
2878 NFSCL_REQSTART(nd, NFSPROC_RENAME, fdvp, cred);
2879 if (nd->nd_flag & ND_NFSV4) {
2880 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2881 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2882 NFSWCCATTR_ATTRBIT(&attrbits);
2883 (void) nfsrv_putattrbit(nd, &attrbits);
2884 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2885 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2886 (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh,
2887 VTONFS(tdvp)->n_fhp->nfh_len, 0);
2888 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2889 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2890 (void) nfsrv_putattrbit(nd, &attrbits);
2891 nd->nd_flag |= ND_V4WCCATTR;
2892 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2893 *tl = txdr_unsigned(NFSV4OP_RENAME);
2894 }
2895 (void) nfsm_strtom(nd, fnameptr, fnamelen);
2896 if (!(nd->nd_flag & ND_NFSV4))
2897 (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh,
2898 VTONFS(tdvp)->n_fhp->nfh_len, 0);
2899 (void) nfsm_strtom(nd, tnameptr, tnamelen);
2900 error = nfscl_request(nd, fdvp, p, cred);
2901 if (error)
2902 return (error);
2903 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
2904 /* For NFSv4, parse out any Delereturn replies. */
2905 if (ret > 0 && nd->nd_repstat != 0 &&
2906 (nd->nd_flag & ND_NOMOREDATA)) {
2907 /*
2908 * If the Delegreturn failed, try again without
2909 * it. The server will Recall, as required.
2910 */
2911 m_freem(nd->nd_mrep);
2912 goto tryagain;
2913 }
2914 for (i = 0; i < (ret * 2); i++) {
2915 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
2916 ND_NFSV4) {
2917 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2918 if (*(tl + 1)) {
2919 if (i == 0 && ret > 1) {
2920 /*
2921 * If the Delegreturn failed, try again
2922 * without it. The server will Recall, as
2923 * required.
2924 * If ret > 1, the first iteration of this
2925 * loop is the second DelegReturn result.
2926 */
2927 m_freem(nd->nd_mrep);
2928 goto tryagain;
2929 } else {
2930 nd->nd_flag |= ND_NOMOREDATA;
2931 }
2932 }
2933 }
2934 }
2935 /* Now, the first wcc attribute reply. */
2936 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
2937 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2938 if (*(tl + 1))
2939 nd->nd_flag |= ND_NOMOREDATA;
2940 }
2941 error = nfscl_wcc_data(nd, fdvp, fnap, fattrflagp, NULL, NULL);
2942 /* and the second wcc attribute reply. */
2943 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 &&
2944 !error) {
2945 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2946 if (*(tl + 1))
2947 nd->nd_flag |= ND_NOMOREDATA;
2948 }
2949 if (!error)
2950 error = nfscl_wcc_data(nd, tdvp, tnap, tattrflagp,
2951 NULL, NULL);
2952 }
2953 if (nd->nd_repstat && !error)
2954 error = nd->nd_repstat;
2955 nfsmout:
2956 m_freem(nd->nd_mrep);
2957 return (error);
2958 }
2959
2960 /*
2961 * nfs hard link create rpc
2962 */
2963 int
2964 nfsrpc_link(vnode_t dvp, vnode_t vp, char *name, int namelen,
2965 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
2966 struct nfsvattr *nap, int *attrflagp, int *dattrflagp)
2967 {
2968 u_int32_t *tl;
2969 struct nfsrv_descript nfsd, *nd = &nfsd;
2970 nfsattrbit_t attrbits;
2971 int error = 0;
2972
2973 *attrflagp = 0;
2974 *dattrflagp = 0;
2975 if (namelen > NFS_MAXNAMLEN)
2976 return (ENAMETOOLONG);
2977 NFSCL_REQSTART(nd, NFSPROC_LINK, vp, cred);
2978 if (nd->nd_flag & ND_NFSV4) {
2979 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2980 *tl = txdr_unsigned(NFSV4OP_PUTFH);
2981 }
2982 (void) nfsm_fhtom(nd, VTONFS(dvp)->n_fhp->nfh_fh,
2983 VTONFS(dvp)->n_fhp->nfh_len, 0);
2984 if (nd->nd_flag & ND_NFSV4) {
2985 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2986 *tl = txdr_unsigned(NFSV4OP_GETATTR);
2987 NFSWCCATTR_ATTRBIT(&attrbits);
2988 (void) nfsrv_putattrbit(nd, &attrbits);
2989 nd->nd_flag |= ND_V4WCCATTR;
2990 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2991 *tl = txdr_unsigned(NFSV4OP_LINK);
2992 }
2993 (void) nfsm_strtom(nd, name, namelen);
2994 error = nfscl_request(nd, vp, p, cred);
2995 if (error)
2996 return (error);
2997 if (nd->nd_flag & ND_NFSV3) {
2998 error = nfscl_postop_attr(nd, nap, attrflagp);
2999 if (!error)
3000 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp,
3001 NULL, NULL);
3002 } else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
3003 /*
3004 * First, parse out the PutFH and Getattr result.
3005 */
3006 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3007 if (!(*(tl + 1)))
3008 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3009 if (*(tl + 1))
3010 nd->nd_flag |= ND_NOMOREDATA;
3011 /*
3012 * Get the pre-op attributes.
3013 */
3014 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL);
3015 }
3016 if (nd->nd_repstat && !error)
3017 error = nd->nd_repstat;
3018 nfsmout:
3019 m_freem(nd->nd_mrep);
3020 return (error);
3021 }
3022
3023 /*
3024 * nfs symbolic link create rpc
3025 */
3026 int
3027 nfsrpc_symlink(vnode_t dvp, char *name, int namelen, const char *target,
3028 struct vattr *vap, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
3029 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
3030 int *dattrflagp)
3031 {
3032 u_int32_t *tl;
3033 struct nfsrv_descript nfsd, *nd = &nfsd;
3034 struct nfsmount *nmp;
3035 int slen, error = 0;
3036
3037 *nfhpp = NULL;
3038 *attrflagp = 0;
3039 *dattrflagp = 0;
3040 nmp = VFSTONFS(dvp->v_mount);
3041 slen = strlen(target);
3042 if (slen > NFS_MAXPATHLEN || namelen > NFS_MAXNAMLEN)
3043 return (ENAMETOOLONG);
3044 NFSCL_REQSTART(nd, NFSPROC_SYMLINK, dvp, cred);
3045 if (nd->nd_flag & ND_NFSV4) {
3046 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3047 *tl = txdr_unsigned(NFLNK);
3048 (void) nfsm_strtom(nd, target, slen);
3049 }
3050 (void) nfsm_strtom(nd, name, namelen);
3051 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
3052 nfscl_fillsattr(nd, vap, dvp, 0, 0);
3053 if (!(nd->nd_flag & ND_NFSV4))
3054 (void) nfsm_strtom(nd, target, slen);
3055 if (nd->nd_flag & ND_NFSV2)
3056 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0);
3057 error = nfscl_request(nd, dvp, p, cred);
3058 if (error)
3059 return (error);
3060 if (nd->nd_flag & ND_NFSV4)
3061 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL);
3062 if ((nd->nd_flag & ND_NFSV3) && !error) {
3063 if (!nd->nd_repstat)
3064 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
3065 if (!error)
3066 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp,
3067 NULL, NULL);
3068 }
3069 if (nd->nd_repstat && !error)
3070 error = nd->nd_repstat;
3071 m_freem(nd->nd_mrep);
3072 /*
3073 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
3074 * Only do this if vfs.nfs.ignore_eexist is set.
3075 * Never do this for NFSv4.1 or later minor versions, since sessions
3076 * should guarantee "exactly once" RPC semantics.
3077 */
3078 if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) ||
3079 nmp->nm_minorvers == 0))
3080 error = 0;
3081 return (error);
3082 }
3083
3084 /*
3085 * nfs make dir rpc
3086 */
3087 int
3088 nfsrpc_mkdir(vnode_t dvp, char *name, int namelen, struct vattr *vap,
3089 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
3090 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
3091 int *dattrflagp)
3092 {
3093 u_int32_t *tl;
3094 struct nfsrv_descript nfsd, *nd = &nfsd;
3095 nfsattrbit_t attrbits;
3096 int error = 0;
3097 struct nfsfh *fhp;
3098 struct nfsmount *nmp;
3099
3100 *nfhpp = NULL;
3101 *attrflagp = 0;
3102 *dattrflagp = 0;
3103 nmp = VFSTONFS(dvp->v_mount);
3104 fhp = VTONFS(dvp)->n_fhp;
3105 if (namelen > NFS_MAXNAMLEN)
3106 return (ENAMETOOLONG);
3107 NFSCL_REQSTART(nd, NFSPROC_MKDIR, dvp, cred);
3108 if (nd->nd_flag & ND_NFSV4) {
3109 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3110 *tl = txdr_unsigned(NFDIR);
3111 }
3112 (void) nfsm_strtom(nd, name, namelen);
3113 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0);
3114 if (nd->nd_flag & ND_NFSV4) {
3115 NFSGETATTR_ATTRBIT(&attrbits);
3116 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3117 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
3118 *tl = txdr_unsigned(NFSV4OP_GETATTR);
3119 (void) nfsrv_putattrbit(nd, &attrbits);
3120 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3121 *tl = txdr_unsigned(NFSV4OP_PUTFH);
3122 (void) nfsm_fhtom(nd, fhp->nfh_fh, fhp->nfh_len, 0);
3123 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3124 *tl = txdr_unsigned(NFSV4OP_GETATTR);
3125 (void) nfsrv_putattrbit(nd, &attrbits);
3126 }
3127 error = nfscl_request(nd, dvp, p, cred);
3128 if (error)
3129 return (error);
3130 if (nd->nd_flag & ND_NFSV4)
3131 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL);
3132 if (!nd->nd_repstat && !error) {
3133 if (nd->nd_flag & ND_NFSV4) {
3134 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
3135 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
3136 }
3137 if (!error)
3138 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
3139 if (error == 0 && (nd->nd_flag & ND_NFSV4) != 0) {
3140 /* Get rid of the PutFH and Getattr status values. */
3141 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
3142 /* Load the directory attributes. */
3143 error = nfsm_loadattr(nd, dnap);
3144 if (error == 0)
3145 *dattrflagp = 1;
3146 }
3147 }
3148 if ((nd->nd_flag & ND_NFSV3) && !error)
3149 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL);
3150 if (nd->nd_repstat && !error)
3151 error = nd->nd_repstat;
3152 nfsmout:
3153 m_freem(nd->nd_mrep);
3154 /*
3155 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
3156 * Only do this if vfs.nfs.ignore_eexist is set.
3157 * Never do this for NFSv4.1 or later minor versions, since sessions
3158 * should guarantee "exactly once" RPC semantics.
3159 */
3160 if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) ||
3161 nmp->nm_minorvers == 0))
3162 error = 0;
3163 return (error);
3164 }
3165
3166 /*
3167 * nfs remove directory call
3168 */
3169 int
3170 nfsrpc_rmdir(vnode_t dvp, char *name, int namelen, struct ucred *cred,
3171 NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp)
3172 {
3173 struct nfsrv_descript nfsd, *nd = &nfsd;
3174 int error = 0;
3175
3176 *dattrflagp = 0;
3177 if (namelen > NFS_MAXNAMLEN)
3178 return (ENAMETOOLONG);
3179 NFSCL_REQSTART(nd, NFSPROC_RMDIR, dvp, cred);
3180 (void) nfsm_strtom(nd, name, namelen);
3181 error = nfscl_request(nd, dvp, p, cred);
3182 if (error)
3183 return (error);
3184 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
3185 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL);
3186 if (nd->nd_repstat && !error)
3187 error = nd->nd_repstat;
3188 m_freem(nd->nd_mrep);
3189 /*
3190 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
3191 */
3192 if (error == ENOENT)
3193 error = 0;
3194 return (error);
3195 }
3196
3197 /*
3198 * Readdir rpc.
3199 * Always returns with either uio_resid unchanged, if you are at the
3200 * end of the directory, or uio_resid == 0, with all DIRBLKSIZ chunks
3201 * filled in.
3202 * I felt this would allow caching of directory blocks more easily
3203 * than returning a pertially filled block.
3204 * Directory offset cookies:
3205 * Oh my, what to do with them...
3206 * I can think of three ways to deal with them:
3207 * 1 - have the layer above these RPCs maintain a map between logical
3208 * directory byte offsets and the NFS directory offset cookies
3209 * 2 - pass the opaque directory offset cookies up into userland
3210 * and let the libc functions deal with them, via the system call
3211 * 3 - return them to userland in the "struct dirent", so future versions
3212 * of libc can use them and do whatever is necessary to make things work
3213 * above these rpc calls, in the meantime
3214 * For now, I do #3 by "hiding" the directory offset cookies after the
3215 * d_name field in struct dirent. This is space inside d_reclen that
3216 * will be ignored by anything that doesn't know about them.
3217 * The directory offset cookies are filled in as the last 8 bytes of
3218 * each directory entry, after d_name. Someday, the userland libc
3219 * functions may be able to use these. In the meantime, it satisfies
3220 * OpenBSD's requirements for cookies being returned.
3221 * If expects the directory offset cookie for the read to be in uio_offset
3222 * and returns the one for the next entry after this directory block in
3223 * there, as well.
3224 */
3225 int
3226 nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
3227 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
3228 int *eofp)
3229 {
3230 int len, left;
3231 struct dirent *dp = NULL;
3232 u_int32_t *tl;
3233 nfsquad_t cookie, ncookie;
3234 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
3235 struct nfsnode *dnp = VTONFS(vp);
3236 struct nfsvattr nfsva;
3237 struct nfsrv_descript nfsd, *nd = &nfsd;
3238 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
3239 int reqsize, tryformoredirs = 1, readsize, eof = 0, gotmnton = 0;
3240 u_int64_t dotfileid, dotdotfileid = 0, fakefileno = UINT64_MAX;
3241 char *cp;
3242 nfsattrbit_t attrbits, dattrbits;
3243 u_int32_t rderr, *tl2 = NULL;
3244 size_t tresid;
3245
3246 KASSERT(uiop->uio_iovcnt == 1 &&
3247 (uiop->uio_resid & (DIRBLKSIZ - 1)) == 0,
3248 ("nfs readdirrpc bad uio"));
3249 ncookie.lval[0] = ncookie.lval[1] = 0;
3250 /*
3251 * There is no point in reading a lot more than uio_resid, however
3252 * adding one additional DIRBLKSIZ makes sense. Since uio_resid
3253 * and nm_readdirsize are both exact multiples of DIRBLKSIZ, this
3254 * will never make readsize > nm_readdirsize.
3255 */
3256 readsize = nmp->nm_readdirsize;
3257 if (readsize > uiop->uio_resid)
3258 readsize = uiop->uio_resid + DIRBLKSIZ;
3259
3260 *attrflagp = 0;
3261 if (eofp)
3262 *eofp = 0;
3263 tresid = uiop->uio_resid;
3264 cookie.lval[0] = cookiep->nfsuquad[0];
3265 cookie.lval[1] = cookiep->nfsuquad[1];
3266 nd->nd_mrep = NULL;
3267
3268 /*
3269 * For NFSv4, first create the "." and ".." entries.
3270 */
3271 if (NFSHASNFSV4(nmp)) {
3272 reqsize = 6 * NFSX_UNSIGNED;
3273 NFSGETATTR_ATTRBIT(&dattrbits);
3274 NFSZERO_ATTRBIT(&attrbits);
3275 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID);
3276 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TYPE);
3277 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
3278 NFSATTRBIT_MOUNTEDONFILEID)) {
3279 NFSSETBIT_ATTRBIT(&attrbits,
3280 NFSATTRBIT_MOUNTEDONFILEID);
3281 gotmnton = 1;
3282 } else {
3283 /*
3284 * Must fake it. Use the fileno, except when the
3285 * fsid is != to that of the directory. For that
3286 * case, generate a fake fileno that is not the same.
3287 */
3288 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID);
3289 gotmnton = 0;
3290 }
3291
3292 /*
3293 * Joy, oh joy. For V4 we get to hand craft '.' and '..'.
3294 */
3295 if (uiop->uio_offset == 0) {
3296 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp, cred);
3297 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3298 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
3299 *tl = txdr_unsigned(NFSV4OP_GETATTR);
3300 (void) nfsrv_putattrbit(nd, &attrbits);
3301 error = nfscl_request(nd, vp, p, cred);
3302 if (error)
3303 return (error);
3304 dotfileid = 0; /* Fake out the compiler. */
3305 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
3306 error = nfsm_loadattr(nd, &nfsva);
3307 if (error != 0)
3308 goto nfsmout;
3309 dotfileid = nfsva.na_fileid;
3310 }
3311 if (nd->nd_repstat == 0) {
3312 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
3313 len = fxdr_unsigned(int, *(tl + 4));
3314 if (len > 0 && len <= NFSX_V4FHMAX)
3315 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
3316 else
3317 error = EPERM;
3318 if (!error) {
3319 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
3320 nfsva.na_mntonfileno = UINT64_MAX;
3321 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
3322 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
3323 NULL, NULL, NULL, p, cred);
3324 if (error) {
3325 dotdotfileid = dotfileid;
3326 } else if (gotmnton) {
3327 if (nfsva.na_mntonfileno != UINT64_MAX)
3328 dotdotfileid = nfsva.na_mntonfileno;
3329 else
3330 dotdotfileid = nfsva.na_fileid;
3331 } else if (nfsva.na_filesid[0] ==
3332 dnp->n_vattr.na_filesid[0] &&
3333 nfsva.na_filesid[1] ==
3334 dnp->n_vattr.na_filesid[1]) {
3335 dotdotfileid = nfsva.na_fileid;
3336 } else {
3337 do {
3338 fakefileno--;
3339 } while (fakefileno ==
3340 nfsva.na_fileid);
3341 dotdotfileid = fakefileno;
3342 }
3343 }
3344 } else if (nd->nd_repstat == NFSERR_NOENT) {
3345 /*
3346 * Lookupp returns NFSERR_NOENT when we are
3347 * at the root, so just use the current dir.
3348 */
3349 nd->nd_repstat = 0;
3350 dotdotfileid = dotfileid;
3351 } else {
3352 error = nd->nd_repstat;
3353 }
3354 m_freem(nd->nd_mrep);
3355 if (error)
3356 return (error);
3357 nd->nd_mrep = NULL;
3358 dp = (struct dirent *)uiop->uio_iov->iov_base;
3359 dp->d_pad0 = dp->d_pad1 = 0;
3360 dp->d_off = 0;
3361 dp->d_type = DT_DIR;
3362 dp->d_fileno = dotfileid;
3363 dp->d_namlen = 1;
3364 *((uint64_t *)dp->d_name) = 0; /* Zero pad it. */
3365 dp->d_name[0] = '.';
3366 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER;
3367 /*
3368 * Just make these offset cookie 0.
3369 */
3370 tl = (u_int32_t *)&dp->d_name[8];
3371 *tl++ = 0;
3372 *tl = 0;
3373 blksiz += dp->d_reclen;
3374 uiop->uio_resid -= dp->d_reclen;
3375 uiop->uio_offset += dp->d_reclen;
3376 uiop->uio_iov->iov_base =
3377 (char *)uiop->uio_iov->iov_base + dp->d_reclen;
3378 uiop->uio_iov->iov_len -= dp->d_reclen;
3379 dp = (struct dirent *)uiop->uio_iov->iov_base;
3380 dp->d_pad0 = dp->d_pad1 = 0;
3381 dp->d_off = 0;
3382 dp->d_type = DT_DIR;
3383 dp->d_fileno = dotdotfileid;
3384 dp->d_namlen = 2;
3385 *((uint64_t *)dp->d_name) = 0;
3386 dp->d_name[0] = '.';
3387 dp->d_name[1] = '.';
3388 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER;
3389 /*
3390 * Just make these offset cookie 0.
3391 */
3392 tl = (u_int32_t *)&dp->d_name[8];
3393 *tl++ = 0;
3394 *tl = 0;
3395 blksiz += dp->d_reclen;
3396 uiop->uio_resid -= dp->d_reclen;
3397 uiop->uio_offset += dp->d_reclen;
3398 uiop->uio_iov->iov_base =
3399 (char *)uiop->uio_iov->iov_base + dp->d_reclen;
3400 uiop->uio_iov->iov_len -= dp->d_reclen;
3401 }
3402 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_RDATTRERROR);
3403 } else {
3404 reqsize = 5 * NFSX_UNSIGNED;
3405 }
3406
3407 /*
3408 * Loop around doing readdir rpc's of size readsize.
3409 * The stopping criteria is EOF or buffer full.
3410 */
3411 while (more_dirs && bigenough) {
3412 *attrflagp = 0;
3413 NFSCL_REQSTART(nd, NFSPROC_READDIR, vp, cred);
3414 if (nd->nd_flag & ND_NFSV2) {
3415 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3416 *tl++ = cookie.lval[1];
3417 *tl = txdr_unsigned(readsize);
3418 } else {
3419 NFSM_BUILD(tl, u_int32_t *, reqsize);
3420 *tl++ = cookie.lval[0];
3421 *tl++ = cookie.lval[1];
3422 if (cookie.qval == 0) {
3423 *tl++ = 0;
3424 *tl++ = 0;
3425 } else {
3426 NFSLOCKNODE(dnp);
3427 *tl++ = dnp->n_cookieverf.nfsuquad[0];
3428 *tl++ = dnp->n_cookieverf.nfsuquad[1];
3429 NFSUNLOCKNODE(dnp);
3430 }
3431 if (nd->nd_flag & ND_NFSV4) {
3432 *tl++ = txdr_unsigned(readsize);
3433 *tl = txdr_unsigned(readsize);
3434 (void) nfsrv_putattrbit(nd, &attrbits);
3435 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3436 *tl = txdr_unsigned(NFSV4OP_GETATTR);
3437 (void) nfsrv_putattrbit(nd, &dattrbits);
3438 } else {
3439 *tl = txdr_unsigned(readsize);
3440 }
3441 }
3442 error = nfscl_request(nd, vp, p, cred);
3443 if (error)
3444 return (error);
3445 if (!(nd->nd_flag & ND_NFSV2)) {
3446 if (nd->nd_flag & ND_NFSV3)
3447 error = nfscl_postop_attr(nd, nap, attrflagp);
3448 if (!nd->nd_repstat && !error) {
3449 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3450 NFSLOCKNODE(dnp);
3451 dnp->n_cookieverf.nfsuquad[0] = *tl++;
3452 dnp->n_cookieverf.nfsuquad[1] = *tl;
3453 NFSUNLOCKNODE(dnp);
3454 }
3455 }
3456 if (nd->nd_repstat || error) {
3457 if (!error)
3458 error = nd->nd_repstat;
3459 goto nfsmout;
3460 }
3461 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3462 more_dirs = fxdr_unsigned(int, *tl);
3463 if (!more_dirs)
3464 tryformoredirs = 0;
3465
3466 /* loop through the dir entries, doctoring them to 4bsd form */
3467 while (more_dirs && bigenough) {
3468 if (nd->nd_flag & ND_NFSV4) {
3469 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3470 ncookie.lval[0] = *tl++;
3471 ncookie.lval[1] = *tl++;
3472 len = fxdr_unsigned(int, *tl);
3473 } else if (nd->nd_flag & ND_NFSV3) {
3474 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3475 nfsva.na_fileid = fxdr_hyper(tl);
3476 tl += 2;
3477 len = fxdr_unsigned(int, *tl);
3478 } else {
3479 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
3480 nfsva.na_fileid = fxdr_unsigned(uint64_t,
3481 *tl++);
3482 len = fxdr_unsigned(int, *tl);
3483 }
3484 if (len <= 0 || len > NFS_MAXNAMLEN) {
3485 error = EBADRPC;
3486 goto nfsmout;
3487 }
3488 tlen = roundup2(len, 8);
3489 if (tlen == len)
3490 tlen += 8; /* To ensure null termination. */
3491 left = DIRBLKSIZ - blksiz;
3492 if (_GENERIC_DIRLEN(len) + NFSX_HYPER > left) {
3493 NFSBZERO(uiop->uio_iov->iov_base, left);
3494 dp->d_reclen += left;
3495 uiop->uio_iov->iov_base =
3496 (char *)uiop->uio_iov->iov_base + left;
3497 uiop->uio_iov->iov_len -= left;
3498 uiop->uio_resid -= left;
3499 uiop->uio_offset += left;
3500 blksiz = 0;
3501 }
3502 if (_GENERIC_DIRLEN(len) + NFSX_HYPER >
3503 uiop->uio_resid)
3504 bigenough = 0;
3505 if (bigenough) {
3506 dp = (struct dirent *)uiop->uio_iov->iov_base;
3507 dp->d_pad0 = dp->d_pad1 = 0;
3508 dp->d_off = 0;
3509 dp->d_namlen = len;
3510 dp->d_reclen = _GENERIC_DIRLEN(len) +
3511 NFSX_HYPER;
3512 dp->d_type = DT_UNKNOWN;
3513 blksiz += dp->d_reclen;
3514 if (blksiz == DIRBLKSIZ)
3515 blksiz = 0;
3516 uiop->uio_resid -= DIRHDSIZ;
3517 uiop->uio_offset += DIRHDSIZ;
3518 uiop->uio_iov->iov_base =
3519 (char *)uiop->uio_iov->iov_base + DIRHDSIZ;
3520 uiop->uio_iov->iov_len -= DIRHDSIZ;
3521 error = nfsm_mbufuio(nd, uiop, len);
3522 if (error)
3523 goto nfsmout;
3524 cp = uiop->uio_iov->iov_base;
3525 tlen -= len;
3526 NFSBZERO(cp, tlen);
3527 cp += tlen; /* points to cookie storage */
3528 tl2 = (u_int32_t *)cp;
3529 uiop->uio_iov->iov_base =
3530 (char *)uiop->uio_iov->iov_base + tlen +
3531 NFSX_HYPER;
3532 uiop->uio_iov->iov_len -= tlen + NFSX_HYPER;
3533 uiop->uio_resid -= tlen + NFSX_HYPER;
3534 uiop->uio_offset += (tlen + NFSX_HYPER);
3535 } else {
3536 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
3537 if (error)
3538 goto nfsmout;
3539 }
3540 if (nd->nd_flag & ND_NFSV4) {
3541 rderr = 0;
3542 nfsva.na_mntonfileno = UINT64_MAX;
3543 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
3544 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
3545 NULL, NULL, &rderr, p, cred);
3546 if (error)
3547 goto nfsmout;
3548 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3549 } else if (nd->nd_flag & ND_NFSV3) {
3550 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3551 ncookie.lval[0] = *tl++;
3552 ncookie.lval[1] = *tl++;
3553 } else {
3554 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
3555 ncookie.lval[0] = 0;
3556 ncookie.lval[1] = *tl++;
3557 }
3558 if (bigenough) {
3559 if (nd->nd_flag & ND_NFSV4) {
3560 if (rderr) {
3561 dp->d_fileno = 0;
3562 } else {
3563 if (gotmnton) {
3564 if (nfsva.na_mntonfileno != UINT64_MAX)
3565 dp->d_fileno = nfsva.na_mntonfileno;
3566 else
3567 dp->d_fileno = nfsva.na_fileid;
3568 } else if (nfsva.na_filesid[0] ==
3569 dnp->n_vattr.na_filesid[0] &&
3570 nfsva.na_filesid[1] ==
3571 dnp->n_vattr.na_filesid[1]) {
3572 dp->d_fileno = nfsva.na_fileid;
3573 } else {
3574 do {
3575 fakefileno--;
3576 } while (fakefileno ==
3577 nfsva.na_fileid);
3578 dp->d_fileno = fakefileno;
3579 }
3580 dp->d_type = vtonfs_dtype(nfsva.na_type);
3581 }
3582 } else {
3583 dp->d_fileno = nfsva.na_fileid;
3584 }
3585 *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] =
3586 ncookie.lval[0];
3587 *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] =
3588 ncookie.lval[1];
3589 }
3590 more_dirs = fxdr_unsigned(int, *tl);
3591 }
3592 /*
3593 * If at end of rpc data, get the eof boolean
3594 */
3595 if (!more_dirs) {
3596 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3597 eof = fxdr_unsigned(int, *tl);
3598 if (tryformoredirs)
3599 more_dirs = !eof;
3600 if (nd->nd_flag & ND_NFSV4) {
3601 error = nfscl_postop_attr(nd, nap, attrflagp);
3602 if (error)
3603 goto nfsmout;
3604 }
3605 }
3606 m_freem(nd->nd_mrep);
3607 nd->nd_mrep = NULL;
3608 }
3609 /*
3610 * Fill last record, iff any, out to a multiple of DIRBLKSIZ
3611 * by increasing d_reclen for the last record.
3612 */
3613 if (blksiz > 0) {
3614 left = DIRBLKSIZ - blksiz;
3615 NFSBZERO(uiop->uio_iov->iov_base, left);
3616 dp->d_reclen += left;
3617 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base +
3618 left;
3619 uiop->uio_iov->iov_len -= left;
3620 uiop->uio_resid -= left;
3621 uiop->uio_offset += left;
3622 }
3623
3624 /*
3625 * If returning no data, assume end of file.
3626 * If not bigenough, return not end of file, since you aren't
3627 * returning all the data
3628 * Otherwise, return the eof flag from the server.
3629 */
3630 if (eofp) {
3631 if (tresid == ((size_t)(uiop->uio_resid)))
3632 *eofp = 1;
3633 else if (!bigenough)
3634 *eofp = 0;
3635 else
3636 *eofp = eof;
3637 }
3638
3639 /*
3640 * Add extra empty records to any remaining DIRBLKSIZ chunks.
3641 */
3642 while (uiop->uio_resid > 0 && uiop->uio_resid != tresid) {
3643 dp = (struct dirent *)uiop->uio_iov->iov_base;
3644 NFSBZERO(dp, DIRBLKSIZ);
3645 dp->d_type = DT_UNKNOWN;
3646 tl = (u_int32_t *)&dp->d_name[4];
3647 *tl++ = cookie.lval[0];
3648 *tl = cookie.lval[1];
3649 dp->d_reclen = DIRBLKSIZ;
3650 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base +
3651 DIRBLKSIZ;
3652 uiop->uio_iov->iov_len -= DIRBLKSIZ;
3653 uiop->uio_resid -= DIRBLKSIZ;
3654 uiop->uio_offset += DIRBLKSIZ;
3655 }
3656
3657 nfsmout:
3658 if (nd->nd_mrep != NULL)
3659 m_freem(nd->nd_mrep);
3660 return (error);
3661 }
3662
3663 /*
3664 * NFS V3 readdir plus RPC. Used in place of nfsrpc_readdir().
3665 * (Also used for NFS V4 when mount flag set.)
3666 * (ditto above w.r.t. multiple of DIRBLKSIZ, etc.)
3667 */
3668 int
3669 nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
3670 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
3671 int *eofp)
3672 {
3673 int len, left;
3674 struct dirent *dp = NULL;
3675 u_int32_t *tl;
3676 vnode_t newvp = NULLVP;
3677 struct nfsrv_descript nfsd, *nd = &nfsd;
3678 struct nameidata nami, *ndp = &nami;
3679 struct componentname *cnp = &ndp->ni_cnd;
3680 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
3681 struct nfsnode *dnp = VTONFS(vp), *np;
3682 struct nfsvattr nfsva;
3683 struct nfsfh *nfhp;
3684 nfsquad_t cookie, ncookie;
3685 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
3686 int attrflag, tryformoredirs = 1, eof = 0, gotmnton = 0;
3687 int isdotdot = 0, unlocknewvp = 0;
3688 u_int64_t dotfileid, dotdotfileid = 0, fakefileno = UINT64_MAX;
3689 u_int64_t fileno = 0;
3690 char *cp;
3691 nfsattrbit_t attrbits, dattrbits;
3692 size_t tresid;
3693 u_int32_t *tl2 = NULL, rderr;
3694 struct timespec dctime, ts;
3695 bool attr_ok;
3696
3697 KASSERT(uiop->uio_iovcnt == 1 &&
3698 (uiop->uio_resid & (DIRBLKSIZ - 1)) == 0,
3699 ("nfs readdirplusrpc bad uio"));
3700 ncookie.lval[0] = ncookie.lval[1] = 0;
3701 timespecclear(&dctime);
3702 *attrflagp = 0;
3703 if (eofp != NULL)
3704 *eofp = 0;
3705 ndp->ni_dvp = vp;
3706 nd->nd_mrep = NULL;
3707 cookie.lval[0] = cookiep->nfsuquad[0];
3708 cookie.lval[1] = cookiep->nfsuquad[1];
3709 tresid = uiop->uio_resid;
3710
3711 /*
3712 * For NFSv4, first create the "." and ".." entries.
3713 */
3714 if (NFSHASNFSV4(nmp)) {
3715 NFSGETATTR_ATTRBIT(&dattrbits);
3716 NFSZERO_ATTRBIT(&attrbits);
3717 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID);
3718 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
3719 NFSATTRBIT_MOUNTEDONFILEID)) {
3720 NFSSETBIT_ATTRBIT(&attrbits,
3721 NFSATTRBIT_MOUNTEDONFILEID);
3722 gotmnton = 1;
3723 } else {
3724 /*
3725 * Must fake it. Use the fileno, except when the
3726 * fsid is != to that of the directory. For that
3727 * case, generate a fake fileno that is not the same.
3728 */
3729 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID);
3730 gotmnton = 0;
3731 }
3732
3733 /*
3734 * Joy, oh joy. For V4 we get to hand craft '.' and '..'.
3735 */
3736 if (uiop->uio_offset == 0) {
3737 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp, cred);
3738 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3739 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
3740 *tl = txdr_unsigned(NFSV4OP_GETATTR);
3741 (void) nfsrv_putattrbit(nd, &attrbits);
3742 error = nfscl_request(nd, vp, p, cred);
3743 if (error)
3744 return (error);
3745 dotfileid = 0; /* Fake out the compiler. */
3746 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
3747 error = nfsm_loadattr(nd, &nfsva);
3748 if (error != 0)
3749 goto nfsmout;
3750 dctime = nfsva.na_ctime;
3751 dotfileid = nfsva.na_fileid;
3752 }
3753 if (nd->nd_repstat == 0) {
3754 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
3755 len = fxdr_unsigned(int, *(tl + 4));
3756 if (len > 0 && len <= NFSX_V4FHMAX)
3757 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
3758 else
3759 error = EPERM;
3760 if (!error) {
3761 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
3762 nfsva.na_mntonfileno = UINT64_MAX;
3763 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
3764 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
3765 NULL, NULL, NULL, p, cred);
3766 if (error) {
3767 dotdotfileid = dotfileid;
3768 } else if (gotmnton) {
3769 if (nfsva.na_mntonfileno != UINT64_MAX)
3770 dotdotfileid = nfsva.na_mntonfileno;
3771 else
3772 dotdotfileid = nfsva.na_fileid;
3773 } else if (nfsva.na_filesid[0] ==
3774 dnp->n_vattr.na_filesid[0] &&
3775 nfsva.na_filesid[1] ==
3776 dnp->n_vattr.na_filesid[1]) {
3777 dotdotfileid = nfsva.na_fileid;
3778 } else {
3779 do {
3780 fakefileno--;
3781 } while (fakefileno ==
3782 nfsva.na_fileid);
3783 dotdotfileid = fakefileno;
3784 }
3785 }
3786 } else if (nd->nd_repstat == NFSERR_NOENT) {
3787 /*
3788 * Lookupp returns NFSERR_NOENT when we are
3789 * at the root, so just use the current dir.
3790 */
3791 nd->nd_repstat = 0;
3792 dotdotfileid = dotfileid;
3793 } else {
3794 error = nd->nd_repstat;
3795 }
3796 m_freem(nd->nd_mrep);
3797 if (error)
3798 return (error);
3799 nd->nd_mrep = NULL;
3800 dp = (struct dirent *)uiop->uio_iov->iov_base;
3801 dp->d_pad0 = dp->d_pad1 = 0;
3802 dp->d_off = 0;
3803 dp->d_type = DT_DIR;
3804 dp->d_fileno = dotfileid;
3805 dp->d_namlen = 1;
3806 *((uint64_t *)dp->d_name) = 0; /* Zero pad it. */
3807 dp->d_name[0] = '.';
3808 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER;
3809 /*
3810 * Just make these offset cookie 0.
3811 */
3812 tl = (u_int32_t *)&dp->d_name[8];
3813 *tl++ = 0;
3814 *tl = 0;
3815 blksiz += dp->d_reclen;
3816 uiop->uio_resid -= dp->d_reclen;
3817 uiop->uio_offset += dp->d_reclen;
3818 uiop->uio_iov->iov_base =
3819 (char *)uiop->uio_iov->iov_base + dp->d_reclen;
3820 uiop->uio_iov->iov_len -= dp->d_reclen;
3821 dp = (struct dirent *)uiop->uio_iov->iov_base;
3822 dp->d_pad0 = dp->d_pad1 = 0;
3823 dp->d_off = 0;
3824 dp->d_type = DT_DIR;
3825 dp->d_fileno = dotdotfileid;
3826 dp->d_namlen = 2;
3827 *((uint64_t *)dp->d_name) = 0;
3828 dp->d_name[0] = '.';
3829 dp->d_name[1] = '.';
3830 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER;
3831 /*
3832 * Just make these offset cookie 0.
3833 */
3834 tl = (u_int32_t *)&dp->d_name[8];
3835 *tl++ = 0;
3836 *tl = 0;
3837 blksiz += dp->d_reclen;
3838 uiop->uio_resid -= dp->d_reclen;
3839 uiop->uio_offset += dp->d_reclen;
3840 uiop->uio_iov->iov_base =
3841 (char *)uiop->uio_iov->iov_base + dp->d_reclen;
3842 uiop->uio_iov->iov_len -= dp->d_reclen;
3843 }
3844 NFSREADDIRPLUS_ATTRBIT(&attrbits);
3845 if (gotmnton)
3846 NFSSETBIT_ATTRBIT(&attrbits,
3847 NFSATTRBIT_MOUNTEDONFILEID);
3848 if (!NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
3849 NFSATTRBIT_TIMECREATE))
3850 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMECREATE);
3851 }
3852
3853 /*
3854 * Loop around doing readdir rpc's of size nm_readdirsize.
3855 * The stopping criteria is EOF or buffer full.
3856 */
3857 while (more_dirs && bigenough) {
3858 *attrflagp = 0;
3859 NFSCL_REQSTART(nd, NFSPROC_READDIRPLUS, vp, cred);
3860 NFSM_BUILD(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
3861 *tl++ = cookie.lval[0];
3862 *tl++ = cookie.lval[1];
3863 if (cookie.qval == 0) {
3864 *tl++ = 0;
3865 *tl++ = 0;
3866 } else {
3867 NFSLOCKNODE(dnp);
3868 *tl++ = dnp->n_cookieverf.nfsuquad[0];
3869 *tl++ = dnp->n_cookieverf.nfsuquad[1];
3870 NFSUNLOCKNODE(dnp);
3871 }
3872 *tl++ = txdr_unsigned(nmp->nm_readdirsize);
3873 *tl = txdr_unsigned(nmp->nm_readdirsize);
3874 if (nd->nd_flag & ND_NFSV4) {
3875 (void) nfsrv_putattrbit(nd, &attrbits);
3876 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3877 *tl = txdr_unsigned(NFSV4OP_GETATTR);
3878 (void) nfsrv_putattrbit(nd, &dattrbits);
3879 }
3880 nanouptime(&ts);
3881 error = nfscl_request(nd, vp, p, cred);
3882 if (error)
3883 return (error);
3884 if (nd->nd_flag & ND_NFSV3)
3885 error = nfscl_postop_attr(nd, nap, attrflagp);
3886 if (nd->nd_repstat || error) {
3887 if (!error)
3888 error = nd->nd_repstat;
3889 goto nfsmout;
3890 }
3891 if ((nd->nd_flag & ND_NFSV3) != 0 && *attrflagp != 0)
3892 dctime = nap->na_ctime;
3893 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3894 NFSLOCKNODE(dnp);
3895 dnp->n_cookieverf.nfsuquad[0] = *tl++;
3896 dnp->n_cookieverf.nfsuquad[1] = *tl++;
3897 NFSUNLOCKNODE(dnp);
3898 more_dirs = fxdr_unsigned(int, *tl);
3899 if (!more_dirs)
3900 tryformoredirs = 0;
3901
3902 /* loop through the dir entries, doctoring them to 4bsd form */
3903 while (more_dirs && bigenough) {
3904 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3905 if (nd->nd_flag & ND_NFSV4) {
3906 ncookie.lval[0] = *tl++;
3907 ncookie.lval[1] = *tl++;
3908 } else {
3909 fileno = fxdr_hyper(tl);
3910 tl += 2;
3911 }
3912 len = fxdr_unsigned(int, *tl);
3913 if (len <= 0 || len > NFS_MAXNAMLEN) {
3914 error = EBADRPC;
3915 goto nfsmout;
3916 }
3917 tlen = roundup2(len, 8);
3918 if (tlen == len)
3919 tlen += 8; /* To ensure null termination. */
3920 left = DIRBLKSIZ - blksiz;
3921 if (_GENERIC_DIRLEN(len) + NFSX_HYPER > left) {
3922 NFSBZERO(uiop->uio_iov->iov_base, left);
3923 dp->d_reclen += left;
3924 uiop->uio_iov->iov_base =
3925 (char *)uiop->uio_iov->iov_base + left;
3926 uiop->uio_iov->iov_len -= left;
3927 uiop->uio_resid -= left;
3928 uiop->uio_offset += left;
3929 blksiz = 0;
3930 }
3931 if (_GENERIC_DIRLEN(len) + NFSX_HYPER >
3932 uiop->uio_resid)
3933 bigenough = 0;
3934 if (bigenough) {
3935 dp = (struct dirent *)uiop->uio_iov->iov_base;
3936 dp->d_pad0 = dp->d_pad1 = 0;
3937 dp->d_off = 0;
3938 dp->d_namlen = len;
3939 dp->d_reclen = _GENERIC_DIRLEN(len) +
3940 NFSX_HYPER;
3941 dp->d_type = DT_UNKNOWN;
3942 blksiz += dp->d_reclen;
3943 if (blksiz == DIRBLKSIZ)
3944 blksiz = 0;
3945 uiop->uio_resid -= DIRHDSIZ;
3946 uiop->uio_offset += DIRHDSIZ;
3947 uiop->uio_iov->iov_base =
3948 (char *)uiop->uio_iov->iov_base + DIRHDSIZ;
3949 uiop->uio_iov->iov_len -= DIRHDSIZ;
3950 cnp->cn_nameptr = uiop->uio_iov->iov_base;
3951 cnp->cn_namelen = len;
3952 NFSCNHASHZERO(cnp);
3953 error = nfsm_mbufuio(nd, uiop, len);
3954 if (error)
3955 goto nfsmout;
3956 cp = uiop->uio_iov->iov_base;
3957 tlen -= len;
3958 NFSBZERO(cp, tlen);
3959 cp += tlen; /* points to cookie storage */
3960 tl2 = (u_int32_t *)cp;
3961 if (len == 2 && cnp->cn_nameptr[0] == '.' &&
3962 cnp->cn_nameptr[1] == '.')
3963 isdotdot = 1;
3964 else
3965 isdotdot = 0;
3966 uiop->uio_iov->iov_base =
3967 (char *)uiop->uio_iov->iov_base + tlen +
3968 NFSX_HYPER;
3969 uiop->uio_iov->iov_len -= tlen + NFSX_HYPER;
3970 uiop->uio_resid -= tlen + NFSX_HYPER;
3971 uiop->uio_offset += (tlen + NFSX_HYPER);
3972 } else {
3973 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
3974 if (error)
3975 goto nfsmout;
3976 }
3977 nfhp = NULL;
3978 if (nd->nd_flag & ND_NFSV3) {
3979 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3980 ncookie.lval[0] = *tl++;
3981 ncookie.lval[1] = *tl++;
3982 attrflag = fxdr_unsigned(int, *tl);
3983 if (attrflag) {
3984 error = nfsm_loadattr(nd, &nfsva);
3985 if (error)
3986 goto nfsmout;
3987 }
3988 NFSM_DISSECT(tl,u_int32_t *,NFSX_UNSIGNED);
3989 if (*tl) {
3990 error = nfsm_getfh(nd, &nfhp);
3991 if (error)
3992 goto nfsmout;
3993 }
3994 if (!attrflag && nfhp != NULL) {
3995 free(nfhp, M_NFSFH);
3996 nfhp = NULL;
3997 }
3998 } else {
3999 rderr = 0;
4000 nfsva.na_mntonfileno = 0xffffffff;
4001 error = nfsv4_loadattr(nd, NULL, &nfsva, &nfhp,
4002 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
4003 NULL, NULL, &rderr, p, cred);
4004 if (error)
4005 goto nfsmout;
4006 }
4007
4008 if (bigenough) {
4009 if (nd->nd_flag & ND_NFSV4) {
4010 if (rderr) {
4011 dp->d_fileno = 0;
4012 } else if (gotmnton) {
4013 if (nfsva.na_mntonfileno != 0xffffffff)
4014 dp->d_fileno = nfsva.na_mntonfileno;
4015 else
4016 dp->d_fileno = nfsva.na_fileid;
4017 } else if (nfsva.na_filesid[0] ==
4018 dnp->n_vattr.na_filesid[0] &&
4019 nfsva.na_filesid[1] ==
4020 dnp->n_vattr.na_filesid[1]) {
4021 dp->d_fileno = nfsva.na_fileid;
4022 } else {
4023 do {
4024 fakefileno--;
4025 } while (fakefileno ==
4026 nfsva.na_fileid);
4027 dp->d_fileno = fakefileno;
4028 }
4029 } else {
4030 dp->d_fileno = fileno;
4031 }
4032 *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] =
4033 ncookie.lval[0];
4034 *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] =
4035 ncookie.lval[1];
4036
4037 if (nfhp != NULL) {
4038 attr_ok = true;
4039 if (NFSRV_CMPFH(nfhp->nfh_fh, nfhp->nfh_len,
4040 dnp->n_fhp->nfh_fh, dnp->n_fhp->nfh_len)) {
4041 VREF(vp);
4042 newvp = vp;
4043 unlocknewvp = 0;
4044 free(nfhp, M_NFSFH);
4045 np = dnp;
4046 } else if (isdotdot != 0) {
4047 /*
4048 * Skip doing a nfscl_nget() call for "..".
4049 * There's a race between acquiring the nfs
4050 * node here and lookups that look for the
4051 * directory being read (in the parent).
4052 * It would try to get a lock on ".." here,
4053 * owning the lock on the directory being
4054 * read. Lookup will hold the lock on ".."
4055 * and try to acquire the lock on the
4056 * directory being read.
4057 * If the directory is unlocked/relocked,
4058 * then there is a LOR with the buflock
4059 * vp is relocked.
4060 */
4061 free(nfhp, M_NFSFH);
4062 } else {
4063 error = nfscl_nget(vp->v_mount, vp,
4064 nfhp, cnp, p, &np, LK_EXCLUSIVE);
4065 if (!error) {
4066 newvp = NFSTOV(np);
4067 unlocknewvp = 1;
4068 /*
4069 * If n_localmodtime >= time before RPC,
4070 * then a file modification operation,
4071 * such as VOP_SETATTR() of size, has
4072 * occurred while the Lookup RPC and
4073 * acquisition of the vnode happened. As
4074 * such, the attributes might be stale,
4075 * with possibly an incorrect size.
4076 */
4077 NFSLOCKNODE(np);
4078 if (timespecisset(
4079 &np->n_localmodtime) &&
4080 timespeccmp(&np->n_localmodtime,
4081 &ts, >=)) {
4082 NFSCL_DEBUG(4, "nfsrpc_readdirplus:"
4083 " localmod stale attributes\n");
4084 attr_ok = false;
4085 }
4086 NFSUNLOCKNODE(np);
4087 }
4088 }
4089 nfhp = NULL;
4090 if (newvp != NULLVP) {
4091 if (attr_ok)
4092 error = nfscl_loadattrcache(&newvp,
4093 &nfsva, NULL, 0, 0);
4094 if (error) {
4095 if (unlocknewvp)
4096 vput(newvp);
4097 else
4098 vrele(newvp);
4099 goto nfsmout;
4100 }
4101 dp->d_type =
4102 vtonfs_dtype(np->n_vattr.na_type);
4103 ndp->ni_vp = newvp;
4104 NFSCNHASH(cnp, HASHINIT);
4105 if (cnp->cn_namelen <= NCHNAMLEN &&
4106 ndp->ni_dvp != ndp->ni_vp &&
4107 (newvp->v_type != VDIR ||
4108 dctime.tv_sec != 0)) {
4109 cache_enter_time_flags(ndp->ni_dvp,
4110 ndp->ni_vp, cnp,
4111 &nfsva.na_ctime,
4112 newvp->v_type != VDIR ? NULL :
4113 &dctime, VFS_CACHE_DROPOLD);
4114 }
4115 if (unlocknewvp)
4116 vput(newvp);
4117 else
4118 vrele(newvp);
4119 newvp = NULLVP;
4120 }
4121 }
4122 } else if (nfhp != NULL) {
4123 free(nfhp, M_NFSFH);
4124 }
4125 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4126 more_dirs = fxdr_unsigned(int, *tl);
4127 }
4128 /*
4129 * If at end of rpc data, get the eof boolean
4130 */
4131 if (!more_dirs) {
4132 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4133 eof = fxdr_unsigned(int, *tl);
4134 if (tryformoredirs)
4135 more_dirs = !eof;
4136 if (nd->nd_flag & ND_NFSV4) {
4137 error = nfscl_postop_attr(nd, nap, attrflagp);
4138 if (error)
4139 goto nfsmout;
4140 }
4141 }
4142 m_freem(nd->nd_mrep);
4143 nd->nd_mrep = NULL;
4144 }
4145 /*
4146 * Fill last record, iff any, out to a multiple of DIRBLKSIZ
4147 * by increasing d_reclen for the last record.
4148 */
4149 if (blksiz > 0) {
4150 left = DIRBLKSIZ - blksiz;
4151 NFSBZERO(uiop->uio_iov->iov_base, left);
4152 dp->d_reclen += left;
4153 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base +
4154 left;
4155 uiop->uio_iov->iov_len -= left;
4156 uiop->uio_resid -= left;
4157 uiop->uio_offset += left;
4158 }
4159
4160 /*
4161 * If returning no data, assume end of file.
4162 * If not bigenough, return not end of file, since you aren't
4163 * returning all the data
4164 * Otherwise, return the eof flag from the server.
4165 */
4166 if (eofp != NULL) {
4167 if (tresid == uiop->uio_resid)
4168 *eofp = 1;
4169 else if (!bigenough)
4170 *eofp = 0;
4171 else
4172 *eofp = eof;
4173 }
4174
4175 /*
4176 * Add extra empty records to any remaining DIRBLKSIZ chunks.
4177 */
4178 while (uiop->uio_resid > 0 && uiop->uio_resid != tresid) {
4179 dp = (struct dirent *)uiop->uio_iov->iov_base;
4180 NFSBZERO(dp, DIRBLKSIZ);
4181 dp->d_type = DT_UNKNOWN;
4182 tl = (u_int32_t *)&dp->d_name[4];
4183 *tl++ = cookie.lval[0];
4184 *tl = cookie.lval[1];
4185 dp->d_reclen = DIRBLKSIZ;
4186 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base +
4187 DIRBLKSIZ;
4188 uiop->uio_iov->iov_len -= DIRBLKSIZ;
4189 uiop->uio_resid -= DIRBLKSIZ;
4190 uiop->uio_offset += DIRBLKSIZ;
4191 }
4192
4193 nfsmout:
4194 if (nd->nd_mrep != NULL)
4195 m_freem(nd->nd_mrep);
4196 return (error);
4197 }
4198
4199 /*
4200 * Nfs commit rpc
4201 */
4202 int
4203 nfsrpc_commit(vnode_t vp, u_quad_t offset, int cnt, struct ucred *cred,
4204 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp)
4205 {
4206 u_int32_t *tl;
4207 struct nfsrv_descript nfsd, *nd = &nfsd;
4208 nfsattrbit_t attrbits;
4209 int error;
4210 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
4211
4212 *attrflagp = 0;
4213 NFSCL_REQSTART(nd, NFSPROC_COMMIT, vp, cred);
4214 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
4215 txdr_hyper(offset, tl);
4216 tl += 2;
4217 *tl = txdr_unsigned(cnt);
4218 if (nd->nd_flag & ND_NFSV4) {
4219 /*
4220 * And do a Getattr op.
4221 */
4222 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4223 *tl = txdr_unsigned(NFSV4OP_GETATTR);
4224 NFSGETATTR_ATTRBIT(&attrbits);
4225 (void) nfsrv_putattrbit(nd, &attrbits);
4226 }
4227 error = nfscl_request(nd, vp, p, cred);
4228 if (error)
4229 return (error);
4230 error = nfscl_wcc_data(nd, vp, nap, attrflagp, NULL, NULL);
4231 if (!error && !nd->nd_repstat) {
4232 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
4233 NFSLOCKMNT(nmp);
4234 if (NFSBCMP(nmp->nm_verf, tl, NFSX_VERF)) {
4235 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
4236 nd->nd_repstat = NFSERR_STALEWRITEVERF;
4237 }
4238 NFSUNLOCKMNT(nmp);
4239 if (nd->nd_flag & ND_NFSV4)
4240 error = nfscl_postop_attr(nd, nap, attrflagp);
4241 }
4242 nfsmout:
4243 if (!error && nd->nd_repstat)
4244 error = nd->nd_repstat;
4245 m_freem(nd->nd_mrep);
4246 return (error);
4247 }
4248
4249 /*
4250 * NFS byte range lock rpc.
4251 * (Mostly just calls one of the three lower level RPC routines.)
4252 */
4253 int
4254 nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
4255 int reclaim, struct ucred *cred, NFSPROC_T *p, void *id, int flags)
4256 {
4257 struct nfscllockowner *lp;
4258 struct nfsclclient *clp;
4259 struct nfsfh *nfhp;
4260 struct nfsrv_descript nfsd, *nd = &nfsd;
4261 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
4262 u_int64_t off, len;
4263 off_t start, end;
4264 u_int32_t clidrev = 0;
4265 int error = 0, newone = 0, expireret = 0, retrycnt, donelocally;
4266 int callcnt, dorpc;
4267
4268 /*
4269 * Convert the flock structure into a start and end and do POSIX
4270 * bounds checking.
4271 */
4272 switch (fl->l_whence) {
4273 case SEEK_SET:
4274 case SEEK_CUR:
4275 /*
4276 * Caller is responsible for adding any necessary offset
4277 * when SEEK_CUR is used.
4278 */
4279 start = fl->l_start;
4280 off = fl->l_start;
4281 break;
4282 case SEEK_END:
4283 start = size + fl->l_start;
4284 off = size + fl->l_start;
4285 break;
4286 default:
4287 return (EINVAL);
4288 }
4289 if (start < 0)
4290 return (EINVAL);
4291 if (fl->l_len != 0) {
4292 end = start + fl->l_len - 1;
4293 if (end < start)
4294 return (EINVAL);
4295 }
4296
4297 len = fl->l_len;
4298 if (len == 0)
4299 len = NFS64BITSSET;
4300 retrycnt = 0;
4301 do {
4302 nd->nd_repstat = 0;
4303 if (op == F_GETLK) {
4304 error = nfscl_getcl(vp->v_mount, cred, p, false, true, &clp);
4305 if (error)
4306 return (error);
4307 error = nfscl_lockt(vp, clp, off, len, fl, p, id, flags);
4308 if (!error) {
4309 clidrev = clp->nfsc_clientidrev;
4310 error = nfsrpc_lockt(nd, vp, clp, off, len, fl, cred,
4311 p, id, flags);
4312 } else if (error == -1) {
4313 error = 0;
4314 }
4315 nfscl_clientrelease(clp);
4316 } else if (op == F_UNLCK && fl->l_type == F_UNLCK) {
4317 /*
4318 * We must loop around for all lockowner cases.
4319 */
4320 callcnt = 0;
4321 error = nfscl_getcl(vp->v_mount, cred, p, false, true, &clp);
4322 if (error)
4323 return (error);
4324 do {
4325 error = nfscl_relbytelock(vp, off, len, cred, p, callcnt,
4326 clp, id, flags, &lp, &dorpc);
4327 /*
4328 * If it returns a NULL lp, we're done.
4329 */
4330 if (lp == NULL) {
4331 if (callcnt == 0)
4332 nfscl_clientrelease(clp);
4333 else
4334 nfscl_releasealllocks(clp, vp, p, id, flags);
4335 return (error);
4336 }
4337 if (nmp->nm_clp != NULL)
4338 clidrev = nmp->nm_clp->nfsc_clientidrev;
4339 else
4340 clidrev = 0;
4341 /*
4342 * If the server doesn't support Posix lock semantics,
4343 * only allow locks on the entire file, since it won't
4344 * handle overlapping byte ranges.
4345 * There might still be a problem when a lock
4346 * upgrade/downgrade (read<->write) occurs, since the
4347 * server "might" expect an unlock first?
4348 */
4349 if (dorpc && (lp->nfsl_open->nfso_posixlock ||
4350 (off == 0 && len == NFS64BITSSET))) {
4351 /*
4352 * Since the lock records will go away, we must
4353 * wait for grace and delay here.
4354 */
4355 do {
4356 error = nfsrpc_locku(nd, nmp, lp, off, len,
4357 NFSV4LOCKT_READ, cred, p, 0);
4358 if ((nd->nd_repstat == NFSERR_GRACE ||
4359 nd->nd_repstat == NFSERR_DELAY) &&
4360 error == 0)
4361 (void) nfs_catnap(PZERO, (int)nd->nd_repstat,
4362 "nfs_advlock");
4363 } while ((nd->nd_repstat == NFSERR_GRACE ||
4364 nd->nd_repstat == NFSERR_DELAY) && error == 0);
4365 }
4366 callcnt++;
4367 } while (error == 0 && nd->nd_repstat == 0);
4368 nfscl_releasealllocks(clp, vp, p, id, flags);
4369 } else if (op == F_SETLK) {
4370 error = nfscl_getbytelock(vp, off, len, fl->l_type, cred, p,
4371 NULL, 0, id, flags, NULL, NULL, &lp, &newone, &donelocally);
4372 if (error || donelocally) {
4373 return (error);
4374 }
4375 if (nmp->nm_clp != NULL)
4376 clidrev = nmp->nm_clp->nfsc_clientidrev;
4377 else
4378 clidrev = 0;
4379 nfhp = VTONFS(vp)->n_fhp;
4380 if (!lp->nfsl_open->nfso_posixlock &&
4381 (off != 0 || len != NFS64BITSSET)) {
4382 error = EINVAL;
4383 } else {
4384 error = nfsrpc_lock(nd, nmp, vp, nfhp->nfh_fh,
4385 nfhp->nfh_len, lp, newone, reclaim, off,
4386 len, fl->l_type, cred, p, 0);
4387 }
4388 if (!error)
4389 error = nd->nd_repstat;
4390 nfscl_lockrelease(lp, error, newone);
4391 } else {
4392 error = EINVAL;
4393 }
4394 if (!error)
4395 error = nd->nd_repstat;
4396 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
4397 error == NFSERR_STALEDONTRECOVER ||
4398 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY ||
4399 error == NFSERR_BADSESSION) {
4400 (void) nfs_catnap(PZERO, error, "nfs_advlock");
4401 } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID)
4402 && clidrev != 0) {
4403 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
4404 retrycnt++;
4405 }
4406 } while (error == NFSERR_GRACE ||
4407 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY ||
4408 error == NFSERR_STALEDONTRECOVER || error == NFSERR_STALESTATEID ||
4409 error == NFSERR_BADSESSION ||
4410 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
4411 expireret == 0 && clidrev != 0 && retrycnt < 4));
4412 if (error && retrycnt >= 4)
4413 error = EIO;
4414 return (error);
4415 }
4416
4417 /*
4418 * The lower level routine for the LockT case.
4419 */
4420 int
4421 nfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp,
4422 struct nfsclclient *clp, u_int64_t off, u_int64_t len, struct flock *fl,
4423 struct ucred *cred, NFSPROC_T *p, void *id, int flags)
4424 {
4425 u_int32_t *tl;
4426 int error, type, size;
4427 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
4428 struct nfsnode *np;
4429 struct nfsmount *nmp;
4430 struct nfsclsession *tsep;
4431
4432 nmp = VFSTONFS(vp->v_mount);
4433 NFSCL_REQSTART(nd, NFSPROC_LOCKT, vp, cred);
4434 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
4435 if (fl->l_type == F_RDLCK)
4436 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
4437 else
4438 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
4439 txdr_hyper(off, tl);
4440 tl += 2;
4441 txdr_hyper(len, tl);
4442 tl += 2;
4443 tsep = nfsmnt_mdssession(nmp);
4444 *tl++ = tsep->nfsess_clientid.lval[0];
4445 *tl = tsep->nfsess_clientid.lval[1];
4446 nfscl_filllockowner(id, own, flags);
4447 np = VTONFS(vp);
4448 NFSBCOPY(np->n_fhp->nfh_fh, &own[NFSV4CL_LOCKNAMELEN],
4449 np->n_fhp->nfh_len);
4450 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + np->n_fhp->nfh_len);
4451 error = nfscl_request(nd, vp, p, cred);
4452 if (error)
4453 return (error);
4454 if (nd->nd_repstat == 0) {
4455 fl->l_type = F_UNLCK;
4456 } else if (nd->nd_repstat == NFSERR_DENIED) {
4457 nd->nd_repstat = 0;
4458 fl->l_whence = SEEK_SET;
4459 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
4460 fl->l_start = fxdr_hyper(tl);
4461 tl += 2;
4462 len = fxdr_hyper(tl);
4463 tl += 2;
4464 if (len == NFS64BITSSET)
4465 fl->l_len = 0;
4466 else
4467 fl->l_len = len;
4468 type = fxdr_unsigned(int, *tl++);
4469 if (type == NFSV4LOCKT_WRITE)
4470 fl->l_type = F_WRLCK;
4471 else
4472 fl->l_type = F_RDLCK;
4473 /*
4474 * XXX For now, I have no idea what to do with the
4475 * conflicting lock_owner, so I'll just set the pid == 0
4476 * and skip over the lock_owner.
4477 */
4478 fl->l_pid = (pid_t)0;
4479 tl += 2;
4480 size = fxdr_unsigned(int, *tl);
4481 if (size < 0 || size > NFSV4_OPAQUELIMIT)
4482 error = EBADRPC;
4483 if (!error)
4484 error = nfsm_advance(nd, NFSM_RNDUP(size), -1);
4485 } else if (nd->nd_repstat == NFSERR_STALECLIENTID)
4486 nfscl_initiate_recovery(clp);
4487 nfsmout:
4488 m_freem(nd->nd_mrep);
4489 return (error);
4490 }
4491
4492 /*
4493 * Lower level function that performs the LockU RPC.
4494 */
4495 static int
4496 nfsrpc_locku(struct nfsrv_descript *nd, struct nfsmount *nmp,
4497 struct nfscllockowner *lp, u_int64_t off, u_int64_t len,
4498 u_int32_t type, struct ucred *cred, NFSPROC_T *p, int syscred)
4499 {
4500 u_int32_t *tl;
4501 int error;
4502
4503 nfscl_reqstart(nd, NFSPROC_LOCKU, nmp, lp->nfsl_open->nfso_fh,
4504 lp->nfsl_open->nfso_fhlen, NULL, NULL, 0, 0, cred);
4505 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
4506 *tl++ = txdr_unsigned(type);
4507 *tl = txdr_unsigned(lp->nfsl_seqid);
4508 if (nfstest_outofseq &&
4509 (arc4random() % nfstest_outofseq) == 0)
4510 *tl = txdr_unsigned(lp->nfsl_seqid + 1);
4511 tl++;
4512 if (NFSHASNFSV4N(nmp))
4513 *tl++ = 0;
4514 else
4515 *tl++ = lp->nfsl_stateid.seqid;
4516 *tl++ = lp->nfsl_stateid.other[0];
4517 *tl++ = lp->nfsl_stateid.other[1];
4518 *tl++ = lp->nfsl_stateid.other[2];
4519 txdr_hyper(off, tl);
4520 tl += 2;
4521 txdr_hyper(len, tl);
4522 if (syscred)
4523 nd->nd_flag |= ND_USEGSSNAME;
4524 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4525 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4526 NFSCL_INCRSEQID(lp->nfsl_seqid, nd);
4527 if (error)
4528 return (error);
4529 if (nd->nd_repstat == 0) {
4530 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
4531 lp->nfsl_stateid.seqid = *tl++;
4532 lp->nfsl_stateid.other[0] = *tl++;
4533 lp->nfsl_stateid.other[1] = *tl++;
4534 lp->nfsl_stateid.other[2] = *tl;
4535 } else if (nd->nd_repstat == NFSERR_STALESTATEID)
4536 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp);
4537 nfsmout:
4538 m_freem(nd->nd_mrep);
4539 return (error);
4540 }
4541
4542 /*
4543 * The actual Lock RPC.
4544 */
4545 int
4546 nfsrpc_lock(struct nfsrv_descript *nd, struct nfsmount *nmp, vnode_t vp,
4547 u_int8_t *nfhp, int fhlen, struct nfscllockowner *lp, int newone,
4548 int reclaim, u_int64_t off, u_int64_t len, short type, struct ucred *cred,
4549 NFSPROC_T *p, int syscred)
4550 {
4551 u_int32_t *tl;
4552 int error, size;
4553 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
4554 struct nfsclsession *tsep;
4555
4556 nfscl_reqstart(nd, NFSPROC_LOCK, nmp, nfhp, fhlen, NULL, NULL, 0, 0,
4557 cred);
4558 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
4559 if (type == F_RDLCK)
4560 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
4561 else
4562 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
4563 *tl++ = txdr_unsigned(reclaim);
4564 txdr_hyper(off, tl);
4565 tl += 2;
4566 txdr_hyper(len, tl);
4567 tl += 2;
4568 if (newone) {
4569 *tl = newnfs_true;
4570 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID +
4571 2 * NFSX_UNSIGNED + NFSX_HYPER);
4572 *tl++ = txdr_unsigned(lp->nfsl_open->nfso_own->nfsow_seqid);
4573 if (NFSHASNFSV4N(nmp))
4574 *tl++ = 0;
4575 else
4576 *tl++ = lp->nfsl_open->nfso_stateid.seqid;
4577 *tl++ = lp->nfsl_open->nfso_stateid.other[0];
4578 *tl++ = lp->nfsl_open->nfso_stateid.other[1];
4579 *tl++ = lp->nfsl_open->nfso_stateid.other[2];
4580 *tl++ = txdr_unsigned(lp->nfsl_seqid);
4581 tsep = nfsmnt_mdssession(nmp);
4582 *tl++ = tsep->nfsess_clientid.lval[0];
4583 *tl = tsep->nfsess_clientid.lval[1];
4584 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN);
4585 NFSBCOPY(nfhp, &own[NFSV4CL_LOCKNAMELEN], fhlen);
4586 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen);
4587 } else {
4588 *tl = newnfs_false;
4589 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
4590 if (NFSHASNFSV4N(nmp))
4591 *tl++ = 0;
4592 else
4593 *tl++ = lp->nfsl_stateid.seqid;
4594 *tl++ = lp->nfsl_stateid.other[0];
4595 *tl++ = lp->nfsl_stateid.other[1];
4596 *tl++ = lp->nfsl_stateid.other[2];
4597 *tl = txdr_unsigned(lp->nfsl_seqid);
4598 if (nfstest_outofseq &&
4599 (arc4random() % nfstest_outofseq) == 0)
4600 *tl = txdr_unsigned(lp->nfsl_seqid + 1);
4601 }
4602 if (syscred)
4603 nd->nd_flag |= ND_USEGSSNAME;
4604 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
4605 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4606 if (error)
4607 return (error);
4608 if (newone)
4609 NFSCL_INCRSEQID(lp->nfsl_open->nfso_own->nfsow_seqid, nd);
4610 NFSCL_INCRSEQID(lp->nfsl_seqid, nd);
4611 if (nd->nd_repstat == 0) {
4612 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
4613 lp->nfsl_stateid.seqid = *tl++;
4614 lp->nfsl_stateid.other[0] = *tl++;
4615 lp->nfsl_stateid.other[1] = *tl++;
4616 lp->nfsl_stateid.other[2] = *tl;
4617 } else if (nd->nd_repstat == NFSERR_DENIED) {
4618 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
4619 size = fxdr_unsigned(int, *(tl + 7));
4620 if (size < 0 || size > NFSV4_OPAQUELIMIT)
4621 error = EBADRPC;
4622 if (!error)
4623 error = nfsm_advance(nd, NFSM_RNDUP(size), -1);
4624 } else if (nd->nd_repstat == NFSERR_STALESTATEID)
4625 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp);
4626 nfsmout:
4627 m_freem(nd->nd_mrep);
4628 return (error);
4629 }
4630
4631 /*
4632 * nfs statfs rpc
4633 * (always called with the vp for the mount point)
4634 */
4635 int
4636 nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp,
4637 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp)
4638 {
4639 u_int32_t *tl = NULL;
4640 struct nfsrv_descript nfsd, *nd = &nfsd;
4641 struct nfsmount *nmp;
4642 nfsattrbit_t attrbits;
4643 int error;
4644
4645 *attrflagp = 0;
4646 nmp = VFSTONFS(vp->v_mount);
4647 if (NFSHASNFSV4(nmp)) {
4648 /*
4649 * For V4, you actually do a getattr.
4650 */
4651 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp, cred);
4652 NFSSTATFS_GETATTRBIT(&attrbits);
4653 (void) nfsrv_putattrbit(nd, &attrbits);
4654 nd->nd_flag |= ND_USEGSSNAME;
4655 error = nfscl_request(nd, vp, p, cred);
4656 if (error)
4657 return (error);
4658 if (nd->nd_repstat == 0) {
4659 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
4660 NULL, NULL, sbp, fsp, NULL, 0, NULL, NULL, NULL, p,
4661 cred);
4662 if (!error) {
4663 nmp->nm_fsid[0] = nap->na_filesid[0];
4664 nmp->nm_fsid[1] = nap->na_filesid[1];
4665 NFSSETHASSETFSID(nmp);
4666 *attrflagp = 1;
4667 }
4668 } else {
4669 error = nd->nd_repstat;
4670 }
4671 if (error)
4672 goto nfsmout;
4673 } else {
4674 NFSCL_REQSTART(nd, NFSPROC_FSSTAT, vp, NULL);
4675 error = nfscl_request(nd, vp, p, cred);
4676 if (error)
4677 return (error);
4678 if (nd->nd_flag & ND_NFSV3) {
4679 error = nfscl_postop_attr(nd, nap, attrflagp);
4680 if (error)
4681 goto nfsmout;
4682 }
4683 if (nd->nd_repstat) {
4684 error = nd->nd_repstat;
4685 goto nfsmout;
4686 }
4687 NFSM_DISSECT(tl, u_int32_t *,
4688 NFSX_STATFS(nd->nd_flag & ND_NFSV3));
4689 }
4690 if (NFSHASNFSV3(nmp)) {
4691 sbp->sf_tbytes = fxdr_hyper(tl); tl += 2;
4692 sbp->sf_fbytes = fxdr_hyper(tl); tl += 2;
4693 sbp->sf_abytes = fxdr_hyper(tl); tl += 2;
4694 sbp->sf_tfiles = fxdr_hyper(tl); tl += 2;
4695 sbp->sf_ffiles = fxdr_hyper(tl); tl += 2;
4696 sbp->sf_afiles = fxdr_hyper(tl); tl += 2;
4697 sbp->sf_invarsec = fxdr_unsigned(u_int32_t, *tl);
4698 } else if (NFSHASNFSV4(nmp) == 0) {
4699 sbp->sf_tsize = fxdr_unsigned(u_int32_t, *tl++);
4700 sbp->sf_bsize = fxdr_unsigned(u_int32_t, *tl++);
4701 sbp->sf_blocks = fxdr_unsigned(u_int32_t, *tl++);
4702 sbp->sf_bfree = fxdr_unsigned(u_int32_t, *tl++);
4703 sbp->sf_bavail = fxdr_unsigned(u_int32_t, *tl);
4704 }
4705 nfsmout:
4706 m_freem(nd->nd_mrep);
4707 return (error);
4708 }
4709
4710 /*
4711 * nfs pathconf rpc
4712 */
4713 int
4714 nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc,
4715 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp)
4716 {
4717 struct nfsrv_descript nfsd, *nd = &nfsd;
4718 struct nfsmount *nmp;
4719 u_int32_t *tl;
4720 nfsattrbit_t attrbits;
4721 int error;
4722
4723 *attrflagp = 0;
4724 nmp = VFSTONFS(vp->v_mount);
4725 if (NFSHASNFSV4(nmp)) {
4726 /*
4727 * For V4, you actually do a getattr.
4728 */
4729 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp, cred);
4730 NFSPATHCONF_GETATTRBIT(&attrbits);
4731 (void) nfsrv_putattrbit(nd, &attrbits);
4732 nd->nd_flag |= ND_USEGSSNAME;
4733 error = nfscl_request(nd, vp, p, cred);
4734 if (error)
4735 return (error);
4736 if (nd->nd_repstat == 0) {
4737 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
4738 pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, p,
4739 cred);
4740 if (!error)
4741 *attrflagp = 1;
4742 } else {
4743 error = nd->nd_repstat;
4744 }
4745 } else {
4746 NFSCL_REQSTART(nd, NFSPROC_PATHCONF, vp, NULL);
4747 error = nfscl_request(nd, vp, p, cred);
4748 if (error)
4749 return (error);
4750 error = nfscl_postop_attr(nd, nap, attrflagp);
4751 if (nd->nd_repstat && !error)
4752 error = nd->nd_repstat;
4753 if (!error) {
4754 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3PATHCONF);
4755 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl++);
4756 pc->pc_namemax = fxdr_unsigned(u_int32_t, *tl++);
4757 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl++);
4758 pc->pc_chownrestricted =
4759 fxdr_unsigned(u_int32_t, *tl++);
4760 pc->pc_caseinsensitive =
4761 fxdr_unsigned(u_int32_t, *tl++);
4762 pc->pc_casepreserving = fxdr_unsigned(u_int32_t, *tl);
4763 }
4764 }
4765 nfsmout:
4766 m_freem(nd->nd_mrep);
4767 return (error);
4768 }
4769
4770 /*
4771 * nfs version 3 fsinfo rpc call
4772 */
4773 int
4774 nfsrpc_fsinfo(vnode_t vp, struct nfsfsinfo *fsp, struct ucred *cred,
4775 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp)
4776 {
4777 u_int32_t *tl;
4778 struct nfsrv_descript nfsd, *nd = &nfsd;
4779 int error;
4780
4781 *attrflagp = 0;
4782 NFSCL_REQSTART(nd, NFSPROC_FSINFO, vp, NULL);
4783 error = nfscl_request(nd, vp, p, cred);
4784 if (error)
4785 return (error);
4786 error = nfscl_postop_attr(nd, nap, attrflagp);
4787 if (nd->nd_repstat && !error)
4788 error = nd->nd_repstat;
4789 if (!error) {
4790 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3FSINFO);
4791 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *tl++);
4792 fsp->fs_rtpref = fxdr_unsigned(u_int32_t, *tl++);
4793 fsp->fs_rtmult = fxdr_unsigned(u_int32_t, *tl++);
4794 fsp->fs_wtmax = fxdr_unsigned(u_int32_t, *tl++);
4795 fsp->fs_wtpref = fxdr_unsigned(u_int32_t, *tl++);
4796 fsp->fs_wtmult = fxdr_unsigned(u_int32_t, *tl++);
4797 fsp->fs_dtpref = fxdr_unsigned(u_int32_t, *tl++);
4798 fsp->fs_maxfilesize = fxdr_hyper(tl);
4799 tl += 2;
4800 fxdr_nfsv3time(tl, &fsp->fs_timedelta);
4801 tl += 2;
4802 fsp->fs_properties = fxdr_unsigned(u_int32_t, *tl);
4803 }
4804 nfsmout:
4805 m_freem(nd->nd_mrep);
4806 return (error);
4807 }
4808
4809 /*
4810 * This function performs the Renew RPC.
4811 */
4812 int
4813 nfsrpc_renew(struct nfsclclient *clp, struct nfsclds *dsp, struct ucred *cred,
4814 NFSPROC_T *p)
4815 {
4816 u_int32_t *tl;
4817 struct nfsrv_descript nfsd;
4818 struct nfsrv_descript *nd = &nfsd;
4819 struct nfsmount *nmp;
4820 int error;
4821 struct nfssockreq *nrp;
4822 struct nfsclsession *tsep;
4823
4824 nmp = clp->nfsc_nmp;
4825 if (nmp == NULL)
4826 return (0);
4827 if (dsp == NULL)
4828 nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL, NULL, 0,
4829 0, cred);
4830 else
4831 nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL,
4832 &dsp->nfsclds_sess, 0, 0, NULL);
4833 if (!NFSHASNFSV4N(nmp)) {
4834 /* NFSv4.1 just uses a Sequence Op and not a Renew. */
4835 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4836 tsep = nfsmnt_mdssession(nmp);
4837 *tl++ = tsep->nfsess_clientid.lval[0];
4838 *tl = tsep->nfsess_clientid.lval[1];
4839 }
4840 nrp = NULL;
4841 if (dsp != NULL)
4842 nrp = dsp->nfsclds_sockp;
4843 if (nrp == NULL)
4844 /* If NULL, use the MDS socket. */
4845 nrp = &nmp->nm_sockreq;
4846 nd->nd_flag |= ND_USEGSSNAME;
4847 if (dsp == NULL)
4848 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
4849 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4850 else {
4851 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
4852 NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
4853 if (error == ENXIO)
4854 nfscl_cancelreqs(dsp);
4855 }
4856 if (error)
4857 return (error);
4858 error = nd->nd_repstat;
4859 m_freem(nd->nd_mrep);
4860 return (error);
4861 }
4862
4863 /*
4864 * This function performs the Releaselockowner RPC.
4865 */
4866 int
4867 nfsrpc_rellockown(struct nfsmount *nmp, struct nfscllockowner *lp,
4868 uint8_t *fh, int fhlen, struct ucred *cred, NFSPROC_T *p)
4869 {
4870 struct nfsrv_descript nfsd, *nd = &nfsd;
4871 u_int32_t *tl;
4872 int error;
4873 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
4874 struct nfsclsession *tsep;
4875
4876 if (NFSHASNFSV4N(nmp)) {
4877 /* For NFSv4.1, do a FreeStateID. */
4878 nfscl_reqstart(nd, NFSPROC_FREESTATEID, nmp, NULL, 0, NULL,
4879 NULL, 0, 0, cred);
4880 nfsm_stateidtom(nd, &lp->nfsl_stateid, NFSSTATEID_PUTSTATEID);
4881 } else {
4882 nfscl_reqstart(nd, NFSPROC_RELEASELCKOWN, nmp, NULL, 0, NULL,
4883 NULL, 0, 0, NULL);
4884 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4885 tsep = nfsmnt_mdssession(nmp);
4886 *tl++ = tsep->nfsess_clientid.lval[0];
4887 *tl = tsep->nfsess_clientid.lval[1];
4888 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN);
4889 NFSBCOPY(fh, &own[NFSV4CL_LOCKNAMELEN], fhlen);
4890 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen);
4891 }
4892 nd->nd_flag |= ND_USEGSSNAME;
4893 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4894 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4895 if (error)
4896 return (error);
4897 error = nd->nd_repstat;
4898 m_freem(nd->nd_mrep);
4899 return (error);
4900 }
4901
4902 /*
4903 * This function performs the Compound to get the mount pt FH.
4904 */
4905 int
4906 nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred,
4907 NFSPROC_T *p)
4908 {
4909 u_int32_t *tl;
4910 struct nfsrv_descript nfsd;
4911 struct nfsrv_descript *nd = &nfsd;
4912 u_char *cp, *cp2;
4913 int error, cnt, len, setnil;
4914 u_int32_t *opcntp;
4915
4916 nfscl_reqstart(nd, NFSPROC_PUTROOTFH, nmp, NULL, 0, &opcntp, NULL, 0,
4917 0, NULL);
4918 cp = dirpath;
4919 cnt = 0;
4920 do {
4921 setnil = 0;
4922 while (*cp == '/')
4923 cp++;
4924 cp2 = cp;
4925 while (*cp2 != '\0' && *cp2 != '/')
4926 cp2++;
4927 if (*cp2 == '/') {
4928 setnil = 1;
4929 *cp2 = '\0';
4930 }
4931 if (cp2 != cp) {
4932 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4933 *tl = txdr_unsigned(NFSV4OP_LOOKUP);
4934 nfsm_strtom(nd, cp, strlen(cp));
4935 cnt++;
4936 }
4937 if (setnil)
4938 *cp2++ = '/';
4939 cp = cp2;
4940 } while (*cp != '\0');
4941 if (NFSHASNFSV4N(nmp))
4942 /* Has a Sequence Op done by nfscl_reqstart(). */
4943 *opcntp = txdr_unsigned(3 + cnt);
4944 else
4945 *opcntp = txdr_unsigned(2 + cnt);
4946 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4947 *tl = txdr_unsigned(NFSV4OP_GETFH);
4948 nd->nd_flag |= ND_USEGSSNAME;
4949 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4950 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4951 if (error)
4952 return (error);
4953 if (nd->nd_repstat == 0) {
4954 NFSM_DISSECT(tl, u_int32_t *, (3 + 2 * cnt) * NFSX_UNSIGNED);
4955 tl += (2 + 2 * cnt);
4956 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
4957 len > NFSX_FHMAX) {
4958 nd->nd_repstat = NFSERR_BADXDR;
4959 } else {
4960 nd->nd_repstat = nfsrv_mtostr(nd, nmp->nm_fh, len);
4961 if (nd->nd_repstat == 0)
4962 nmp->nm_fhsize = len;
4963 }
4964 }
4965 error = nd->nd_repstat;
4966 nfsmout:
4967 m_freem(nd->nd_mrep);
4968 return (error);
4969 }
4970
4971 /*
4972 * This function performs the Delegreturn RPC.
4973 */
4974 int
4975 nfsrpc_delegreturn(struct nfscldeleg *dp, struct ucred *cred,
4976 struct nfsmount *nmp, NFSPROC_T *p, int syscred)
4977 {
4978 u_int32_t *tl;
4979 struct nfsrv_descript nfsd;
4980 struct nfsrv_descript *nd = &nfsd;
4981 int error;
4982
4983 nfscl_reqstart(nd, NFSPROC_DELEGRETURN, nmp, dp->nfsdl_fh,
4984 dp->nfsdl_fhlen, NULL, NULL, 0, 0, cred);
4985 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
4986 if (NFSHASNFSV4N(nmp))
4987 *tl++ = 0;
4988 else
4989 *tl++ = dp->nfsdl_stateid.seqid;
4990 *tl++ = dp->nfsdl_stateid.other[0];
4991 *tl++ = dp->nfsdl_stateid.other[1];
4992 *tl = dp->nfsdl_stateid.other[2];
4993 if (syscred)
4994 nd->nd_flag |= ND_USEGSSNAME;
4995 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4996 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4997 if (error)
4998 return (error);
4999 error = nd->nd_repstat;
5000 m_freem(nd->nd_mrep);
5001 return (error);
5002 }
5003
5004 /*
5005 * nfs getacl call.
5006 */
5007 int
5008 nfsrpc_getacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p, struct acl *aclp)
5009 {
5010 struct nfsrv_descript nfsd, *nd = &nfsd;
5011 int error;
5012 nfsattrbit_t attrbits;
5013 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
5014
5015 if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp))
5016 return (EOPNOTSUPP);
5017 NFSCL_REQSTART(nd, NFSPROC_GETACL, vp, cred);
5018 NFSZERO_ATTRBIT(&attrbits);
5019 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
5020 (void) nfsrv_putattrbit(nd, &attrbits);
5021 error = nfscl_request(nd, vp, p, cred);
5022 if (error)
5023 return (error);
5024 if (!nd->nd_repstat)
5025 error = nfsv4_loadattr(nd, vp, NULL, NULL, NULL, 0, NULL,
5026 NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, p, cred);
5027 else
5028 error = nd->nd_repstat;
5029 m_freem(nd->nd_mrep);
5030 return (error);
5031 }
5032
5033 /*
5034 * nfs setacl call.
5035 */
5036 int
5037 nfsrpc_setacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p, struct acl *aclp)
5038 {
5039 int error;
5040 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
5041
5042 if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp))
5043 return (EOPNOTSUPP);
5044 error = nfsrpc_setattr(vp, NULL, aclp, cred, p, NULL, NULL);
5045 return (error);
5046 }
5047
5048 /*
5049 * nfs setacl call.
5050 */
5051 static int
5052 nfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
5053 struct acl *aclp, nfsv4stateid_t *stateidp)
5054 {
5055 struct nfsrv_descript nfsd, *nd = &nfsd;
5056 int error;
5057 nfsattrbit_t attrbits;
5058 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
5059
5060 if (!NFSHASNFSV4(nmp))
5061 return (EOPNOTSUPP);
5062 NFSCL_REQSTART(nd, NFSPROC_SETACL, vp, cred);
5063 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
5064 NFSZERO_ATTRBIT(&attrbits);
5065 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
5066 (void) nfsv4_fillattr(nd, vp->v_mount, vp, aclp, NULL, NULL, 0,
5067 &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL);
5068 error = nfscl_request(nd, vp, p, cred);
5069 if (error)
5070 return (error);
5071 /* Don't care about the pre/postop attributes */
5072 m_freem(nd->nd_mrep);
5073 return (nd->nd_repstat);
5074 }
5075
5076 /*
5077 * Do the NFSv4.1 Exchange ID.
5078 */
5079 int
5080 nfsrpc_exchangeid(struct nfsmount *nmp, struct nfsclclient *clp,
5081 struct nfssockreq *nrp, int minorvers, uint32_t exchflags,
5082 struct nfsclds **dspp, struct ucred *cred, NFSPROC_T *p)
5083 {
5084 uint32_t *tl, v41flags;
5085 struct nfsrv_descript nfsd;
5086 struct nfsrv_descript *nd = &nfsd;
5087 struct nfsclds *dsp;
5088 struct timespec verstime;
5089 int error, len;
5090
5091 *dspp = NULL;
5092 if (minorvers == 0)
5093 minorvers = nmp->nm_minorvers;
5094 nfscl_reqstart(nd, NFSPROC_EXCHANGEID, nmp, NULL, 0, NULL, NULL,
5095 NFS_VER4, minorvers, NULL);
5096 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
5097 *tl++ = txdr_unsigned(nfsboottime.tv_sec); /* Client owner */
5098 *tl = txdr_unsigned(clp->nfsc_rev);
5099 (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen);
5100
5101 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
5102 *tl++ = txdr_unsigned(exchflags);
5103 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE);
5104
5105 /* Set the implementation id4 */
5106 *tl = txdr_unsigned(1);
5107 (void) nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
5108 (void) nfsm_strtom(nd, version, strlen(version));
5109 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
5110 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */
5111 verstime.tv_nsec = 0;
5112 txdr_nfsv4time(&verstime, tl);
5113 nd->nd_flag |= ND_USEGSSNAME;
5114 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
5115 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5116 NFSCL_DEBUG(1, "exchangeid err=%d reps=%d\n", error,
5117 (int)nd->nd_repstat);
5118 if (error != 0)
5119 return (error);
5120 if (nd->nd_repstat == 0) {
5121 NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_UNSIGNED + NFSX_HYPER);
5122 len = fxdr_unsigned(int, *(tl + 7));
5123 if (len < 0 || len > NFSV4_OPAQUELIMIT) {
5124 error = NFSERR_BADXDR;
5125 goto nfsmout;
5126 }
5127 dsp = malloc(sizeof(struct nfsclds) + len + 1, M_NFSCLDS,
5128 M_WAITOK | M_ZERO);
5129 dsp->nfsclds_expire = NFSD_MONOSEC + clp->nfsc_renew;
5130 dsp->nfsclds_servownlen = len;
5131 dsp->nfsclds_sess.nfsess_clientid.lval[0] = *tl++;
5132 dsp->nfsclds_sess.nfsess_clientid.lval[1] = *tl++;
5133 dsp->nfsclds_sess.nfsess_sequenceid =
5134 fxdr_unsigned(uint32_t, *tl++);
5135 v41flags = fxdr_unsigned(uint32_t, *tl);
5136 if ((v41flags & NFSV4EXCH_USEPNFSMDS) != 0 &&
5137 NFSHASPNFSOPT(nmp)) {
5138 NFSCL_DEBUG(1, "set PNFS\n");
5139 NFSLOCKMNT(nmp);
5140 nmp->nm_state |= NFSSTA_PNFS;
5141 NFSUNLOCKMNT(nmp);
5142 dsp->nfsclds_flags |= NFSCLDS_MDS;
5143 }
5144 if ((v41flags & NFSV4EXCH_USEPNFSDS) != 0)
5145 dsp->nfsclds_flags |= NFSCLDS_DS;
5146 if (minorvers == NFSV42_MINORVERSION)
5147 dsp->nfsclds_flags |= NFSCLDS_MINORV2;
5148 if (len > 0)
5149 nd->nd_repstat = nfsrv_mtostr(nd,
5150 dsp->nfsclds_serverown, len);
5151 if (nd->nd_repstat == 0) {
5152 mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF);
5153 mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession",
5154 NULL, MTX_DEF);
5155 nfscl_initsessionslots(&dsp->nfsclds_sess);
5156 *dspp = dsp;
5157 } else
5158 free(dsp, M_NFSCLDS);
5159 }
5160 error = nd->nd_repstat;
5161 nfsmout:
5162 m_freem(nd->nd_mrep);
5163 return (error);
5164 }
5165
5166 /*
5167 * Do the NFSv4.1 Create Session.
5168 */
5169 int
5170 nfsrpc_createsession(struct nfsmount *nmp, struct nfsclsession *sep,
5171 struct nfssockreq *nrp, struct nfsclds *dsp, uint32_t sequenceid, int mds,
5172 struct ucred *cred, NFSPROC_T *p)
5173 {
5174 uint32_t crflags, maxval, *tl;
5175 struct nfsrv_descript nfsd;
5176 struct nfsrv_descript *nd = &nfsd;
5177 int error, irdcnt, minorvers;
5178
5179 /* Make sure nm_rsize, nm_wsize is set. */
5180 if (nmp->nm_rsize > NFS_MAXBSIZE || nmp->nm_rsize == 0)
5181 nmp->nm_rsize = NFS_MAXBSIZE;
5182 if (nmp->nm_wsize > NFS_MAXBSIZE || nmp->nm_wsize == 0)
5183 nmp->nm_wsize = NFS_MAXBSIZE;
5184 if (dsp == NULL)
5185 minorvers = nmp->nm_minorvers;
5186 else if ((dsp->nfsclds_flags & NFSCLDS_MINORV2) != 0)
5187 minorvers = NFSV42_MINORVERSION;
5188 else
5189 minorvers = NFSV41_MINORVERSION;
5190 nfscl_reqstart(nd, NFSPROC_CREATESESSION, nmp, NULL, 0, NULL, NULL,
5191 NFS_VER4, minorvers, NULL);
5192 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED);
5193 *tl++ = sep->nfsess_clientid.lval[0];
5194 *tl++ = sep->nfsess_clientid.lval[1];
5195 *tl++ = txdr_unsigned(sequenceid);
5196 crflags = (NFSMNT_RDONLY(nmp->nm_mountp) ? 0 : NFSV4CRSESS_PERSIST);
5197 if (nfscl_enablecallb != 0 && nfs_numnfscbd > 0 && mds != 0)
5198 crflags |= NFSV4CRSESS_CONNBACKCHAN;
5199 *tl = txdr_unsigned(crflags);
5200
5201 /* Fill in fore channel attributes. */
5202 NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED);
5203 *tl++ = 0; /* Header pad size */
5204 if ((nd->nd_flag & ND_NFSV42) != 0 && mds != 0 && sb_max_adj >=
5205 nmp->nm_wsize && sb_max_adj >= nmp->nm_rsize) {
5206 /*
5207 * NFSv4.2 Extended Attribute operations may want to do
5208 * requests/replies that are larger than nm_rsize/nm_wsize.
5209 */
5210 *tl++ = txdr_unsigned(sb_max_adj - NFS_MAXXDR);
5211 *tl++ = txdr_unsigned(sb_max_adj - NFS_MAXXDR);
5212 } else {
5213 *tl++ = txdr_unsigned(nmp->nm_wsize + NFS_MAXXDR);
5214 *tl++ = txdr_unsigned(nmp->nm_rsize + NFS_MAXXDR);
5215 }
5216 *tl++ = txdr_unsigned(4096); /* Max response size cached */
5217 *tl++ = txdr_unsigned(20); /* Max operations */
5218 *tl++ = txdr_unsigned(64); /* Max slots */
5219 *tl = 0; /* No rdma ird */
5220
5221 /* Fill in back channel attributes. */
5222 NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED);
5223 *tl++ = 0; /* Header pad size */
5224 *tl++ = txdr_unsigned(10000); /* Max request size */
5225 *tl++ = txdr_unsigned(10000); /* Max response size */
5226 *tl++ = txdr_unsigned(4096); /* Max response size cached */
5227 *tl++ = txdr_unsigned(4); /* Max operations */
5228 *tl++ = txdr_unsigned(NFSV4_CBSLOTS); /* Max slots */
5229 *tl = 0; /* No rdma ird */
5230
5231 NFSM_BUILD(tl, uint32_t *, 8 * NFSX_UNSIGNED);
5232 *tl++ = txdr_unsigned(NFS_CALLBCKPROG); /* Call back prog # */
5233
5234 /* Allow AUTH_SYS callbacks as uid, gid == 0. */
5235 *tl++ = txdr_unsigned(1); /* Auth_sys only */
5236 *tl++ = txdr_unsigned(AUTH_SYS); /* AUTH_SYS type */
5237 *tl++ = txdr_unsigned(nfsboottime.tv_sec); /* time stamp */
5238 *tl++ = 0; /* Null machine name */
5239 *tl++ = 0; /* Uid == 0 */
5240 *tl++ = 0; /* Gid == 0 */
5241 *tl = 0; /* No additional gids */
5242 nd->nd_flag |= ND_USEGSSNAME;
5243 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, NFS_PROG,
5244 NFS_VER4, NULL, 1, NULL, NULL);
5245 if (error != 0)
5246 return (error);
5247 if (nd->nd_repstat == 0) {
5248 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID +
5249 2 * NFSX_UNSIGNED);
5250 bcopy(tl, sep->nfsess_sessionid, NFSX_V4SESSIONID);
5251 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
5252 sep->nfsess_sequenceid = fxdr_unsigned(uint32_t, *tl++);
5253 crflags = fxdr_unsigned(uint32_t, *tl);
5254 if ((crflags & NFSV4CRSESS_PERSIST) != 0 && mds != 0) {
5255 NFSLOCKMNT(nmp);
5256 nmp->nm_state |= NFSSTA_SESSPERSIST;
5257 NFSUNLOCKMNT(nmp);
5258 }
5259
5260 /* Get the fore channel slot count. */
5261 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
5262 tl++; /* Skip the header pad size. */
5263
5264 /* Make sure nm_wsize is small enough. */
5265 maxval = fxdr_unsigned(uint32_t, *tl++);
5266 while (maxval < nmp->nm_wsize + NFS_MAXXDR) {
5267 if (nmp->nm_wsize > 8096)
5268 nmp->nm_wsize /= 2;
5269 else
5270 break;
5271 }
5272 sep->nfsess_maxreq = maxval;
5273
5274 /* Make sure nm_rsize is small enough. */
5275 maxval = fxdr_unsigned(uint32_t, *tl++);
5276 while (maxval < nmp->nm_rsize + NFS_MAXXDR) {
5277 if (nmp->nm_rsize > 8096)
5278 nmp->nm_rsize /= 2;
5279 else
5280 break;
5281 }
5282 sep->nfsess_maxresp = maxval;
5283
5284 sep->nfsess_maxcache = fxdr_unsigned(int, *tl++);
5285 tl++;
5286 sep->nfsess_foreslots = fxdr_unsigned(uint16_t, *tl++);
5287 NFSCL_DEBUG(4, "fore slots=%d\n", (int)sep->nfsess_foreslots);
5288 irdcnt = fxdr_unsigned(int, *tl);
5289 if (irdcnt < 0 || irdcnt > 1) {
5290 error = NFSERR_BADXDR;
5291 goto nfsmout;
5292 }
5293 if (irdcnt > 0)
5294 NFSM_DISSECT(tl, uint32_t *, irdcnt * NFSX_UNSIGNED);
5295
5296 /* and the back channel slot count. */
5297 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
5298 tl += 5;
5299 sep->nfsess_backslots = fxdr_unsigned(uint16_t, *tl);
5300 NFSCL_DEBUG(4, "back slots=%d\n", (int)sep->nfsess_backslots);
5301 }
5302 error = nd->nd_repstat;
5303 nfsmout:
5304 m_freem(nd->nd_mrep);
5305 return (error);
5306 }
5307
5308 /*
5309 * Do the NFSv4.1 Destroy Client.
5310 */
5311 int
5312 nfsrpc_destroyclient(struct nfsmount *nmp, struct nfsclclient *clp,
5313 struct ucred *cred, NFSPROC_T *p)
5314 {
5315 uint32_t *tl;
5316 struct nfsrv_descript nfsd;
5317 struct nfsrv_descript *nd = &nfsd;
5318 int error;
5319 struct nfsclsession *tsep;
5320
5321 nfscl_reqstart(nd, NFSPROC_DESTROYCLIENT, nmp, NULL, 0, NULL, NULL, 0,
5322 0, NULL);
5323 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
5324 tsep = nfsmnt_mdssession(nmp);
5325 *tl++ = tsep->nfsess_clientid.lval[0];
5326 *tl = tsep->nfsess_clientid.lval[1];
5327 nd->nd_flag |= ND_USEGSSNAME;
5328 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5329 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5330 if (error != 0)
5331 return (error);
5332 error = nd->nd_repstat;
5333 m_freem(nd->nd_mrep);
5334 return (error);
5335 }
5336
5337 /*
5338 * Do the NFSv4.1 LayoutGet.
5339 */
5340 static int
5341 nfsrpc_layoutget(struct nfsmount *nmp, uint8_t *fhp, int fhlen, int iomode,
5342 uint64_t offset, uint64_t len, uint64_t minlen, int layouttype,
5343 int layoutlen, nfsv4stateid_t *stateidp, int *retonclosep,
5344 struct nfsclflayouthead *flhp, struct ucred *cred, NFSPROC_T *p)
5345 {
5346 struct nfsrv_descript nfsd, *nd = &nfsd;
5347 int error;
5348
5349 nfscl_reqstart(nd, NFSPROC_LAYOUTGET, nmp, fhp, fhlen, NULL, NULL, 0,
5350 0, cred);
5351 nfsrv_setuplayoutget(nd, iomode, offset, len, minlen, stateidp,
5352 layouttype, layoutlen, 0);
5353 nd->nd_flag |= ND_USEGSSNAME;
5354 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5355 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5356 NFSCL_DEBUG(4, "layget err=%d st=%d\n", error, nd->nd_repstat);
5357 if (error != 0)
5358 return (error);
5359 if (nd->nd_repstat == 0)
5360 error = nfsrv_parselayoutget(nmp, nd, stateidp, retonclosep,
5361 flhp);
5362 if (error == 0 && nd->nd_repstat != 0)
5363 error = nd->nd_repstat;
5364 m_freem(nd->nd_mrep);
5365 return (error);
5366 }
5367
5368 /*
5369 * Do the NFSv4.1 Get Device Info.
5370 */
5371 int
5372 nfsrpc_getdeviceinfo(struct nfsmount *nmp, uint8_t *deviceid, int layouttype,
5373 uint32_t *notifybitsp, struct nfscldevinfo **ndip, struct ucred *cred,
5374 NFSPROC_T *p)
5375 {
5376 uint32_t cnt, *tl, vers, minorvers;
5377 struct nfsrv_descript nfsd;
5378 struct nfsrv_descript *nd = &nfsd;
5379 struct sockaddr_in sin, ssin;
5380 struct sockaddr_in6 sin6, ssin6;
5381 struct nfsclds *dsp = NULL, **dspp, **gotdspp;
5382 struct nfscldevinfo *ndi;
5383 int addrcnt = 0, bitcnt, error, gotminor, gotvers, i, isudp, j;
5384 int stripecnt;
5385 uint8_t stripeindex;
5386 sa_family_t af, safilled;
5387
5388 ssin.sin_port = 0; /* To shut up compiler. */
5389 ssin.sin_addr.s_addr = 0; /* ditto */
5390 *ndip = NULL;
5391 ndi = NULL;
5392 gotdspp = NULL;
5393 nfscl_reqstart(nd, NFSPROC_GETDEVICEINFO, nmp, NULL, 0, NULL, NULL, 0,
5394 0, cred);
5395 NFSM_BUILD(tl, uint32_t *, NFSX_V4DEVICEID + 3 * NFSX_UNSIGNED);
5396 NFSBCOPY(deviceid, tl, NFSX_V4DEVICEID);
5397 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5398 *tl++ = txdr_unsigned(layouttype);
5399 *tl++ = txdr_unsigned(100000);
5400 if (notifybitsp != NULL && *notifybitsp != 0) {
5401 *tl = txdr_unsigned(1); /* One word of bits. */
5402 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5403 *tl = txdr_unsigned(*notifybitsp);
5404 } else
5405 *tl = txdr_unsigned(0);
5406 nd->nd_flag |= ND_USEGSSNAME;
5407 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5408 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5409 if (error != 0)
5410 return (error);
5411 if (nd->nd_repstat == 0) {
5412 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
5413 if (layouttype != fxdr_unsigned(int, *tl))
5414 printf("EEK! devinfo layout type not same!\n");
5415 if (layouttype == NFSLAYOUT_NFSV4_1_FILES) {
5416 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5417 stripecnt = fxdr_unsigned(int, *tl);
5418 NFSCL_DEBUG(4, "stripecnt=%d\n", stripecnt);
5419 if (stripecnt < 1 || stripecnt > 4096) {
5420 printf("pNFS File layout devinfo stripecnt %d:"
5421 " out of range\n", stripecnt);
5422 error = NFSERR_BADXDR;
5423 goto nfsmout;
5424 }
5425 NFSM_DISSECT(tl, uint32_t *, (stripecnt + 1) *
5426 NFSX_UNSIGNED);
5427 addrcnt = fxdr_unsigned(int, *(tl + stripecnt));
5428 NFSCL_DEBUG(4, "addrcnt=%d\n", addrcnt);
5429 if (addrcnt < 1 || addrcnt > 128) {
5430 printf("NFS devinfo addrcnt %d: out of range\n",
5431 addrcnt);
5432 error = NFSERR_BADXDR;
5433 goto nfsmout;
5434 }
5435
5436 /*
5437 * Now we know how many stripe indices and addresses, so
5438 * we can allocate the structure the correct size.
5439 */
5440 i = (stripecnt * sizeof(uint8_t)) /
5441 sizeof(struct nfsclds *) + 1;
5442 NFSCL_DEBUG(4, "stripeindices=%d\n", i);
5443 ndi = malloc(sizeof(*ndi) + (addrcnt + i) *
5444 sizeof(struct nfsclds *), M_NFSDEVINFO, M_WAITOK |
5445 M_ZERO);
5446 NFSBCOPY(deviceid, ndi->nfsdi_deviceid,
5447 NFSX_V4DEVICEID);
5448 ndi->nfsdi_refcnt = 0;
5449 ndi->nfsdi_flags = NFSDI_FILELAYOUT;
5450 ndi->nfsdi_stripecnt = stripecnt;
5451 ndi->nfsdi_addrcnt = addrcnt;
5452 /* Fill in the stripe indices. */
5453 for (i = 0; i < stripecnt; i++) {
5454 stripeindex = fxdr_unsigned(uint8_t, *tl++);
5455 NFSCL_DEBUG(4, "stripeind=%d\n", stripeindex);
5456 if (stripeindex >= addrcnt) {
5457 printf("pNFS File Layout devinfo"
5458 " stripeindex %d: too big\n",
5459 (int)stripeindex);
5460 error = NFSERR_BADXDR;
5461 goto nfsmout;
5462 }
5463 nfsfldi_setstripeindex(ndi, i, stripeindex);
5464 }
5465 } else if (layouttype == NFSLAYOUT_FLEXFILE) {
5466 /* For Flex File, we only get one address list. */
5467 ndi = malloc(sizeof(*ndi) + sizeof(struct nfsclds *),
5468 M_NFSDEVINFO, M_WAITOK | M_ZERO);
5469 NFSBCOPY(deviceid, ndi->nfsdi_deviceid,
5470 NFSX_V4DEVICEID);
5471 ndi->nfsdi_refcnt = 0;
5472 ndi->nfsdi_flags = NFSDI_FLEXFILE;
5473 addrcnt = ndi->nfsdi_addrcnt = 1;
5474 }
5475
5476 /* Now, dissect the server address(es). */
5477 safilled = AF_UNSPEC;
5478 for (i = 0; i < addrcnt; i++) {
5479 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5480 cnt = fxdr_unsigned(uint32_t, *tl);
5481 if (cnt == 0) {
5482 printf("NFS devinfo 0 len addrlist\n");
5483 error = NFSERR_BADXDR;
5484 goto nfsmout;
5485 }
5486 dspp = nfsfldi_addr(ndi, i);
5487 safilled = AF_UNSPEC;
5488 for (j = 0; j < cnt; j++) {
5489 error = nfsv4_getipaddr(nd, &sin, &sin6, &af,
5490 &isudp);
5491 if (error != 0 && error != EPERM) {
5492 error = NFSERR_BADXDR;
5493 goto nfsmout;
5494 }
5495 if (error == 0 && isudp == 0) {
5496 /*
5497 * The priority is:
5498 * - Same address family.
5499 * Save the address and dspp, so that
5500 * the connection can be done after
5501 * parsing is complete.
5502 */
5503 if (safilled == AF_UNSPEC ||
5504 (af == nmp->nm_nam->sa_family &&
5505 safilled != nmp->nm_nam->sa_family)
5506 ) {
5507 if (af == AF_INET)
5508 ssin = sin;
5509 else
5510 ssin6 = sin6;
5511 safilled = af;
5512 gotdspp = dspp;
5513 }
5514 }
5515 }
5516 }
5517
5518 gotvers = NFS_VER4; /* Default NFSv4.1 for File Layout. */
5519 gotminor = NFSV41_MINORVERSION;
5520 /* For Flex File, we will take one of the versions to use. */
5521 if (layouttype == NFSLAYOUT_FLEXFILE) {
5522 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5523 j = fxdr_unsigned(int, *tl);
5524 if (j < 1 || j > NFSDEV_MAXVERS) {
5525 printf("pNFS: too many versions\n");
5526 error = NFSERR_BADXDR;
5527 goto nfsmout;
5528 }
5529 gotvers = 0;
5530 gotminor = 0;
5531 for (i = 0; i < j; i++) {
5532 NFSM_DISSECT(tl, uint32_t *, 5 * NFSX_UNSIGNED);
5533 vers = fxdr_unsigned(uint32_t, *tl++);
5534 minorvers = fxdr_unsigned(uint32_t, *tl++);
5535 if (vers == NFS_VER3)
5536 minorvers = 0;
5537 if ((vers == NFS_VER4 && ((minorvers ==
5538 NFSV41_MINORVERSION && gotminor == 0) ||
5539 minorvers == NFSV42_MINORVERSION)) ||
5540 (vers == NFS_VER3 && gotvers == 0)) {
5541 gotvers = vers;
5542 gotminor = minorvers;
5543 /* We'll take this one. */
5544 ndi->nfsdi_versindex = i;
5545 ndi->nfsdi_vers = vers;
5546 ndi->nfsdi_minorvers = minorvers;
5547 ndi->nfsdi_rsize = fxdr_unsigned(
5548 uint32_t, *tl++);
5549 ndi->nfsdi_wsize = fxdr_unsigned(
5550 uint32_t, *tl++);
5551 if (*tl == newnfs_true)
5552 ndi->nfsdi_flags |=
5553 NFSDI_TIGHTCOUPLED;
5554 else
5555 ndi->nfsdi_flags &=
5556 ~NFSDI_TIGHTCOUPLED;
5557 }
5558 }
5559 if (gotvers == 0) {
5560 printf("pNFS: no NFSv3, NFSv4.1 or NFSv4.2\n");
5561 error = NFSERR_BADXDR;
5562 goto nfsmout;
5563 }
5564 }
5565
5566 /* And the notify bits. */
5567 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5568 bitcnt = fxdr_unsigned(int, *tl);
5569 if (bitcnt > 0) {
5570 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5571 if (notifybitsp != NULL)
5572 *notifybitsp =
5573 fxdr_unsigned(uint32_t, *tl);
5574 }
5575 if (safilled != AF_UNSPEC) {
5576 KASSERT(ndi != NULL, ("ndi is NULL"));
5577 *ndip = ndi;
5578 } else
5579 error = EPERM;
5580 if (error == 0) {
5581 /*
5582 * Now we can do a TCP connection for the correct
5583 * NFS version and IP address.
5584 */
5585 error = nfsrpc_fillsa(nmp, &ssin, &ssin6, safilled,
5586 gotvers, gotminor, &dsp, p);
5587 }
5588 if (error == 0) {
5589 KASSERT(gotdspp != NULL, ("gotdspp is NULL"));
5590 *gotdspp = dsp;
5591 }
5592 }
5593 if (nd->nd_repstat != 0 && error == 0)
5594 error = nd->nd_repstat;
5595 nfsmout:
5596 if (error != 0 && ndi != NULL)
5597 nfscl_freedevinfo(ndi);
5598 m_freem(nd->nd_mrep);
5599 return (error);
5600 }
5601
5602 /*
5603 * Do the NFSv4.1 LayoutCommit.
5604 */
5605 int
5606 nfsrpc_layoutcommit(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim,
5607 uint64_t off, uint64_t len, uint64_t lastbyte, nfsv4stateid_t *stateidp,
5608 int layouttype, struct ucred *cred, NFSPROC_T *p)
5609 {
5610 uint32_t *tl;
5611 struct nfsrv_descript nfsd, *nd = &nfsd;
5612 int error;
5613
5614 nfscl_reqstart(nd, NFSPROC_LAYOUTCOMMIT, nmp, fh, fhlen, NULL, NULL,
5615 0, 0, cred);
5616 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
5617 NFSX_STATEID);
5618 txdr_hyper(off, tl);
5619 tl += 2;
5620 txdr_hyper(len, tl);
5621 tl += 2;
5622 if (reclaim != 0)
5623 *tl++ = newnfs_true;
5624 else
5625 *tl++ = newnfs_false;
5626 *tl++ = txdr_unsigned(stateidp->seqid);
5627 *tl++ = stateidp->other[0];
5628 *tl++ = stateidp->other[1];
5629 *tl++ = stateidp->other[2];
5630 *tl++ = newnfs_true;
5631 if (lastbyte < off)
5632 lastbyte = off;
5633 else if (lastbyte >= (off + len))
5634 lastbyte = off + len - 1;
5635 txdr_hyper(lastbyte, tl);
5636 tl += 2;
5637 *tl++ = newnfs_false;
5638 *tl++ = txdr_unsigned(layouttype);
5639 /* All supported layouts are 0 length. */
5640 *tl = txdr_unsigned(0);
5641 nd->nd_flag |= ND_USEGSSNAME;
5642 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5643 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5644 if (error != 0)
5645 return (error);
5646 error = nd->nd_repstat;
5647 m_freem(nd->nd_mrep);
5648 return (error);
5649 }
5650
5651 /*
5652 * Do the NFSv4.1 LayoutReturn.
5653 */
5654 int
5655 nfsrpc_layoutreturn(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim,
5656 int layouttype, uint32_t iomode, int layoutreturn, uint64_t offset,
5657 uint64_t len, nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p,
5658 uint32_t stat, uint32_t op, char *devid)
5659 {
5660 uint32_t *tl;
5661 struct nfsrv_descript nfsd, *nd = &nfsd;
5662 uint64_t tu64;
5663 int error;
5664
5665 nfscl_reqstart(nd, NFSPROC_LAYOUTRETURN, nmp, fh, fhlen, NULL, NULL,
5666 0, 0, cred);
5667 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED);
5668 if (reclaim != 0)
5669 *tl++ = newnfs_true;
5670 else
5671 *tl++ = newnfs_false;
5672 *tl++ = txdr_unsigned(layouttype);
5673 *tl++ = txdr_unsigned(iomode);
5674 *tl = txdr_unsigned(layoutreturn);
5675 if (layoutreturn == NFSLAYOUTRETURN_FILE) {
5676 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
5677 NFSX_UNSIGNED);
5678 txdr_hyper(offset, tl);
5679 tl += 2;
5680 txdr_hyper(len, tl);
5681 tl += 2;
5682 NFSCL_DEBUG(4, "layoutret stseq=%d\n", (int)stateidp->seqid);
5683 *tl++ = txdr_unsigned(stateidp->seqid);
5684 *tl++ = stateidp->other[0];
5685 *tl++ = stateidp->other[1];
5686 *tl++ = stateidp->other[2];
5687 if (layouttype == NFSLAYOUT_NFSV4_1_FILES)
5688 *tl = txdr_unsigned(0);
5689 else if (layouttype == NFSLAYOUT_FLEXFILE) {
5690 if (stat != 0) {
5691 *tl = txdr_unsigned(2 * NFSX_HYPER +
5692 NFSX_STATEID + NFSX_V4DEVICEID + 5 *
5693 NFSX_UNSIGNED);
5694 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER +
5695 NFSX_STATEID + NFSX_V4DEVICEID + 5 *
5696 NFSX_UNSIGNED);
5697 *tl++ = txdr_unsigned(1); /* One error. */
5698 tu64 = 0; /* Offset. */
5699 txdr_hyper(tu64, tl); tl += 2;
5700 tu64 = UINT64_MAX; /* Length. */
5701 txdr_hyper(tu64, tl); tl += 2;
5702 NFSBCOPY(stateidp, tl, NFSX_STATEID);
5703 tl += (NFSX_STATEID / NFSX_UNSIGNED);
5704 *tl++ = txdr_unsigned(1); /* One error. */
5705 NFSBCOPY(devid, tl, NFSX_V4DEVICEID);
5706 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5707 *tl++ = txdr_unsigned(stat);
5708 *tl++ = txdr_unsigned(op);
5709 } else {
5710 *tl = txdr_unsigned(2 * NFSX_UNSIGNED);
5711 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
5712 /* No ioerrs. */
5713 *tl++ = 0;
5714 }
5715 *tl = 0; /* No stats yet. */
5716 }
5717 }
5718 nd->nd_flag |= ND_USEGSSNAME;
5719 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5720 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5721 if (error != 0)
5722 return (error);
5723 if (nd->nd_repstat == 0) {
5724 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5725 if (*tl != 0) {
5726 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
5727 stateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
5728 stateidp->other[0] = *tl++;
5729 stateidp->other[1] = *tl++;
5730 stateidp->other[2] = *tl;
5731 }
5732 } else
5733 error = nd->nd_repstat;
5734 nfsmout:
5735 m_freem(nd->nd_mrep);
5736 return (error);
5737 }
5738
5739 /*
5740 * Do the NFSv4.2 LayoutError.
5741 */
5742 static int
5743 nfsrpc_layouterror(struct nfsmount *nmp, uint8_t *fh, int fhlen, uint64_t offset,
5744 uint64_t len, nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p,
5745 uint32_t stat, uint32_t op, char *devid)
5746 {
5747 uint32_t *tl;
5748 struct nfsrv_descript nfsd, *nd = &nfsd;
5749 int error;
5750
5751 nfscl_reqstart(nd, NFSPROC_LAYOUTERROR, nmp, fh, fhlen, NULL, NULL,
5752 0, 0, cred);
5753 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
5754 NFSX_V4DEVICEID + 3 * NFSX_UNSIGNED);
5755 txdr_hyper(offset, tl); tl += 2;
5756 txdr_hyper(len, tl); tl += 2;
5757 *tl++ = txdr_unsigned(stateidp->seqid);
5758 *tl++ = stateidp->other[0];
5759 *tl++ = stateidp->other[1];
5760 *tl++ = stateidp->other[2];
5761 *tl++ = txdr_unsigned(1);
5762 NFSBCOPY(devid, tl, NFSX_V4DEVICEID);
5763 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5764 *tl++ = txdr_unsigned(stat);
5765 *tl = txdr_unsigned(op);
5766 nd->nd_flag |= ND_USEGSSNAME;
5767 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5768 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5769 if (error != 0)
5770 return (error);
5771 if (nd->nd_repstat != 0)
5772 error = nd->nd_repstat;
5773 m_freem(nd->nd_mrep);
5774 return (error);
5775 }
5776
5777 /*
5778 * Acquire a layout and devinfo, if possible. The caller must have acquired
5779 * a reference count on the nfsclclient structure before calling this.
5780 * Return the layout in lypp with a reference count on it, if successful.
5781 */
5782 static int
5783 nfsrpc_getlayout(struct nfsmount *nmp, vnode_t vp, struct nfsfh *nfhp,
5784 int iomode, uint32_t rw, uint32_t *notifybitsp, nfsv4stateid_t *stateidp,
5785 uint64_t off, struct nfscllayout **lypp, struct ucred *cred, NFSPROC_T *p)
5786 {
5787 struct nfscllayout *lyp;
5788 struct nfsclflayout *flp;
5789 struct nfsclflayouthead flh;
5790 int error = 0, islocked, layoutlen, layouttype, recalled, retonclose;
5791 nfsv4stateid_t stateid;
5792 struct nfsclsession *tsep;
5793
5794 *lypp = NULL;
5795 if (NFSHASFLEXFILE(nmp))
5796 layouttype = NFSLAYOUT_FLEXFILE;
5797 else
5798 layouttype = NFSLAYOUT_NFSV4_1_FILES;
5799 /*
5800 * If lyp is returned non-NULL, there will be a refcnt (shared lock)
5801 * on it, iff flp != NULL or a lock (exclusive lock) on it iff
5802 * flp == NULL.
5803 */
5804 lyp = nfscl_getlayout(nmp->nm_clp, nfhp->nfh_fh, nfhp->nfh_len,
5805 off, rw, &flp, &recalled);
5806 islocked = 0;
5807 if (lyp == NULL || flp == NULL) {
5808 if (recalled != 0)
5809 return (EIO);
5810 LIST_INIT(&flh);
5811 tsep = nfsmnt_mdssession(nmp);
5812 layoutlen = tsep->nfsess_maxcache -
5813 (NFSX_STATEID + 3 * NFSX_UNSIGNED);
5814 if (lyp == NULL) {
5815 stateid.seqid = 0;
5816 stateid.other[0] = stateidp->other[0];
5817 stateid.other[1] = stateidp->other[1];
5818 stateid.other[2] = stateidp->other[2];
5819 error = nfsrpc_layoutget(nmp, nfhp->nfh_fh,
5820 nfhp->nfh_len, iomode, (uint64_t)0, UINT64_MAX,
5821 (uint64_t)0, layouttype, layoutlen, &stateid,
5822 &retonclose, &flh, cred, p);
5823 } else {
5824 islocked = 1;
5825 stateid.seqid = lyp->nfsly_stateid.seqid;
5826 stateid.other[0] = lyp->nfsly_stateid.other[0];
5827 stateid.other[1] = lyp->nfsly_stateid.other[1];
5828 stateid.other[2] = lyp->nfsly_stateid.other[2];
5829 error = nfsrpc_layoutget(nmp, nfhp->nfh_fh,
5830 nfhp->nfh_len, iomode, off, UINT64_MAX,
5831 (uint64_t)0, layouttype, layoutlen, &stateid,
5832 &retonclose, &flh, cred, p);
5833 }
5834 error = nfsrpc_layoutgetres(nmp, vp, nfhp->nfh_fh,
5835 nfhp->nfh_len, &stateid, retonclose, notifybitsp, &lyp,
5836 &flh, layouttype, error, NULL, cred, p);
5837 if (error == 0)
5838 *lypp = lyp;
5839 else if (islocked != 0)
5840 nfscl_rellayout(lyp, 1);
5841 } else
5842 *lypp = lyp;
5843 return (error);
5844 }
5845
5846 /*
5847 * Do a TCP connection plus exchange id and create session.
5848 * If successful, a "struct nfsclds" is linked into the list for the
5849 * mount point and a pointer to it is returned.
5850 */
5851 static int
5852 nfsrpc_fillsa(struct nfsmount *nmp, struct sockaddr_in *sin,
5853 struct sockaddr_in6 *sin6, sa_family_t af, int vers, int minorvers,
5854 struct nfsclds **dspp, NFSPROC_T *p)
5855 {
5856 struct sockaddr_in *msad, *sad;
5857 struct sockaddr_in6 *msad6, *sad6;
5858 struct nfsclclient *clp;
5859 struct nfssockreq *nrp;
5860 struct nfsclds *dsp, *tdsp;
5861 int error, firsttry;
5862 enum nfsclds_state retv;
5863 uint32_t sequenceid = 0;
5864
5865 KASSERT(nmp->nm_sockreq.nr_cred != NULL,
5866 ("nfsrpc_fillsa: NULL nr_cred"));
5867 NFSLOCKCLSTATE();
5868 clp = nmp->nm_clp;
5869 NFSUNLOCKCLSTATE();
5870 if (clp == NULL)
5871 return (EPERM);
5872 if (af == AF_INET) {
5873 NFSLOCKMNT(nmp);
5874 /*
5875 * Check to see if we already have a session for this
5876 * address that is usable for a DS.
5877 * Note that the MDS's address is in a different place
5878 * than the sessions already acquired for DS's.
5879 */
5880 msad = (struct sockaddr_in *)nmp->nm_sockreq.nr_nam;
5881 tdsp = TAILQ_FIRST(&nmp->nm_sess);
5882 while (tdsp != NULL) {
5883 if (msad != NULL && msad->sin_family == AF_INET &&
5884 sin->sin_addr.s_addr == msad->sin_addr.s_addr &&
5885 sin->sin_port == msad->sin_port &&
5886 (tdsp->nfsclds_flags & NFSCLDS_DS) != 0 &&
5887 tdsp->nfsclds_sess.nfsess_defunct == 0) {
5888 *dspp = tdsp;
5889 NFSUNLOCKMNT(nmp);
5890 NFSCL_DEBUG(4, "fnd same addr\n");
5891 return (0);
5892 }
5893 tdsp = TAILQ_NEXT(tdsp, nfsclds_list);
5894 if (tdsp != NULL && tdsp->nfsclds_sockp != NULL)
5895 msad = (struct sockaddr_in *)
5896 tdsp->nfsclds_sockp->nr_nam;
5897 else
5898 msad = NULL;
5899 }
5900 NFSUNLOCKMNT(nmp);
5901
5902 /* No IP address match, so look for new/trunked one. */
5903 sad = malloc(sizeof(*sad), M_SONAME, M_WAITOK | M_ZERO);
5904 sad->sin_len = sizeof(*sad);
5905 sad->sin_family = AF_INET;
5906 sad->sin_port = sin->sin_port;
5907 sad->sin_addr.s_addr = sin->sin_addr.s_addr;
5908 nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO);
5909 nrp->nr_nam = (struct sockaddr *)sad;
5910 } else if (af == AF_INET6) {
5911 NFSLOCKMNT(nmp);
5912 /*
5913 * Check to see if we already have a session for this
5914 * address that is usable for a DS.
5915 * Note that the MDS's address is in a different place
5916 * than the sessions already acquired for DS's.
5917 */
5918 msad6 = (struct sockaddr_in6 *)nmp->nm_sockreq.nr_nam;
5919 tdsp = TAILQ_FIRST(&nmp->nm_sess);
5920 while (tdsp != NULL) {
5921 if (msad6 != NULL && msad6->sin6_family == AF_INET6 &&
5922 IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
5923 &msad6->sin6_addr) &&
5924 sin6->sin6_port == msad6->sin6_port &&
5925 (tdsp->nfsclds_flags & NFSCLDS_DS) != 0 &&
5926 tdsp->nfsclds_sess.nfsess_defunct == 0) {
5927 *dspp = tdsp;
5928 NFSUNLOCKMNT(nmp);
5929 return (0);
5930 }
5931 tdsp = TAILQ_NEXT(tdsp, nfsclds_list);
5932 if (tdsp != NULL && tdsp->nfsclds_sockp != NULL)
5933 msad6 = (struct sockaddr_in6 *)
5934 tdsp->nfsclds_sockp->nr_nam;
5935 else
5936 msad6 = NULL;
5937 }
5938 NFSUNLOCKMNT(nmp);
5939
5940 /* No IP address match, so look for new/trunked one. */
5941 sad6 = malloc(sizeof(*sad6), M_SONAME, M_WAITOK | M_ZERO);
5942 sad6->sin6_len = sizeof(*sad6);
5943 sad6->sin6_family = AF_INET6;
5944 sad6->sin6_port = sin6->sin6_port;
5945 NFSBCOPY(&sin6->sin6_addr, &sad6->sin6_addr,
5946 sizeof(struct in6_addr));
5947 nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO);
5948 nrp->nr_nam = (struct sockaddr *)sad6;
5949 } else
5950 return (EPERM);
5951
5952 nrp->nr_sotype = SOCK_STREAM;
5953 mtx_init(&nrp->nr_mtx, "nfssock", NULL, MTX_DEF);
5954 nrp->nr_prog = NFS_PROG;
5955 nrp->nr_vers = vers;
5956
5957 /*
5958 * Use the credentials that were used for the mount, which are
5959 * in nmp->nm_sockreq.nr_cred for newnfs_connect() etc.
5960 * Ref. counting the credentials with crhold() is probably not
5961 * necessary, since nm_sockreq.nr_cred won't be crfree()'d until
5962 * unmount, but I did it anyhow.
5963 */
5964 nrp->nr_cred = crhold(nmp->nm_sockreq.nr_cred);
5965 error = newnfs_connect(nmp, nrp, NULL, p, 0, false, &nrp->nr_client);
5966 NFSCL_DEBUG(3, "DS connect=%d\n", error);
5967
5968 dsp = NULL;
5969 /* Now, do the exchangeid and create session. */
5970 if (error == 0) {
5971 if (vers == NFS_VER4) {
5972 firsttry = 0;
5973 do {
5974 error = nfsrpc_exchangeid(nmp, clp, nrp,
5975 minorvers, NFSV4EXCH_USEPNFSDS, &dsp,
5976 nrp->nr_cred, p);
5977 NFSCL_DEBUG(3, "DS exchangeid=%d\n", error);
5978 if (error == NFSERR_MINORVERMISMATCH)
5979 minorvers = NFSV42_MINORVERSION;
5980 } while (error == NFSERR_MINORVERMISMATCH &&
5981 firsttry++ == 0);
5982 if (error != 0)
5983 newnfs_disconnect(NULL, nrp);
5984 } else {
5985 dsp = malloc(sizeof(struct nfsclds), M_NFSCLDS,
5986 M_WAITOK | M_ZERO);
5987 dsp->nfsclds_flags |= NFSCLDS_DS;
5988 dsp->nfsclds_expire = INT32_MAX; /* No renews needed. */
5989 mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF);
5990 mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession",
5991 NULL, MTX_DEF);
5992 }
5993 }
5994 if (error == 0) {
5995 dsp->nfsclds_sockp = nrp;
5996 if (vers == NFS_VER4) {
5997 NFSLOCKMNT(nmp);
5998 retv = nfscl_getsameserver(nmp, dsp, &tdsp,
5999 &sequenceid);
6000 NFSCL_DEBUG(3, "getsame ret=%d\n", retv);
6001 if (retv == NFSDSP_USETHISSESSION &&
6002 nfscl_dssameconn != 0) {
6003 NFSLOCKDS(tdsp);
6004 tdsp->nfsclds_flags |= NFSCLDS_SAMECONN;
6005 NFSUNLOCKDS(tdsp);
6006 NFSUNLOCKMNT(nmp);
6007 /*
6008 * If there is already a session for this
6009 * server, use it.
6010 */
6011 newnfs_disconnect(NULL, nrp);
6012 nfscl_freenfsclds(dsp);
6013 *dspp = tdsp;
6014 return (0);
6015 }
6016 if (retv == NFSDSP_NOTFOUND)
6017 sequenceid =
6018 dsp->nfsclds_sess.nfsess_sequenceid;
6019 NFSUNLOCKMNT(nmp);
6020 error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess,
6021 nrp, dsp, sequenceid, 0, nrp->nr_cred, p);
6022 NFSCL_DEBUG(3, "DS createsess=%d\n", error);
6023 }
6024 } else {
6025 NFSFREECRED(nrp->nr_cred);
6026 NFSFREEMUTEX(&nrp->nr_mtx);
6027 free(nrp->nr_nam, M_SONAME);
6028 free(nrp, M_NFSSOCKREQ);
6029 }
6030 if (error == 0) {
6031 NFSCL_DEBUG(3, "add DS session\n");
6032 /*
6033 * Put it at the end of the list. That way the list
6034 * is ordered by when the entry was added. This matters
6035 * since the one done first is the one that should be
6036 * used for sequencid'ing any subsequent create sessions.
6037 */
6038 NFSLOCKMNT(nmp);
6039 TAILQ_INSERT_TAIL(&nmp->nm_sess, dsp, nfsclds_list);
6040 NFSUNLOCKMNT(nmp);
6041 *dspp = dsp;
6042 } else if (dsp != NULL) {
6043 newnfs_disconnect(NULL, nrp);
6044 nfscl_freenfsclds(dsp);
6045 }
6046 return (error);
6047 }
6048
6049 /*
6050 * Do the NFSv4.1 Reclaim Complete.
6051 */
6052 int
6053 nfsrpc_reclaimcomplete(struct nfsmount *nmp, struct ucred *cred, NFSPROC_T *p)
6054 {
6055 uint32_t *tl;
6056 struct nfsrv_descript nfsd;
6057 struct nfsrv_descript *nd = &nfsd;
6058 int error;
6059
6060 nfscl_reqstart(nd, NFSPROC_RECLAIMCOMPL, nmp, NULL, 0, NULL, NULL, 0,
6061 0, cred);
6062 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
6063 *tl = newnfs_false;
6064 nd->nd_flag |= ND_USEGSSNAME;
6065 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
6066 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
6067 if (error != 0)
6068 return (error);
6069 error = nd->nd_repstat;
6070 m_freem(nd->nd_mrep);
6071 return (error);
6072 }
6073
6074 /*
6075 * Initialize the slot tables for a session.
6076 */
6077 static void
6078 nfscl_initsessionslots(struct nfsclsession *sep)
6079 {
6080 int i;
6081
6082 for (i = 0; i < NFSV4_CBSLOTS; i++) {
6083 if (sep->nfsess_cbslots[i].nfssl_reply != NULL)
6084 m_freem(sep->nfsess_cbslots[i].nfssl_reply);
6085 NFSBZERO(&sep->nfsess_cbslots[i], sizeof(struct nfsslot));
6086 }
6087 for (i = 0; i < 64; i++)
6088 sep->nfsess_slotseq[i] = 0;
6089 sep->nfsess_slots = 0;
6090 sep->nfsess_badslots = 0;
6091 }
6092
6093 /*
6094 * Called to try and do an I/O operation via an NFSv4.1 Data Server (DS).
6095 */
6096 int
6097 nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
6098 uint32_t rwaccess, int docommit, struct ucred *cred, NFSPROC_T *p)
6099 {
6100 struct nfsnode *np = VTONFS(vp);
6101 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
6102 struct nfscllayout *layp;
6103 struct nfscldevinfo *dip;
6104 struct nfsclflayout *rflp;
6105 struct mbuf *m, *m2;
6106 struct nfsclwritedsdorpc *drpc, *tdrpc;
6107 nfsv4stateid_t stateid;
6108 struct ucred *newcred;
6109 uint64_t lastbyte, len, off, oresid, xfer;
6110 int eof, error, firstmirror, i, iolaymode, mirrorcnt, recalled, timo;
6111 void *lckp;
6112 uint8_t *dev;
6113 void *iovbase = NULL;
6114 size_t iovlen = 0;
6115 off_t offs = 0;
6116 ssize_t resid = 0;
6117 uint32_t op;
6118
6119 if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || nfs_numnfscbd == 0 ||
6120 (np->n_flag & NNOLAYOUT) != 0)
6121 return (EIO);
6122 /* Now, get a reference cnt on the clientid for this mount. */
6123 if (nfscl_getref(nmp) == 0)
6124 return (EIO);
6125
6126 /* Find an appropriate stateid. */
6127 newcred = NFSNEWCRED(cred);
6128 error = nfscl_getstateid(vp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len,
6129 rwaccess, 1, newcred, p, &stateid, &lckp);
6130 if (error != 0) {
6131 NFSFREECRED(newcred);
6132 nfscl_relref(nmp);
6133 return (error);
6134 }
6135 /* Search for a layout for this file. */
6136 off = uiop->uio_offset;
6137 layp = nfscl_getlayout(nmp->nm_clp, np->n_fhp->nfh_fh,
6138 np->n_fhp->nfh_len, off, rwaccess, &rflp, &recalled);
6139 if (layp == NULL || rflp == NULL) {
6140 if (recalled != 0) {
6141 NFSFREECRED(newcred);
6142 if (lckp != NULL)
6143 nfscl_lockderef(lckp);
6144 nfscl_relref(nmp);
6145 return (EIO);
6146 }
6147 if (layp != NULL) {
6148 nfscl_rellayout(layp, (rflp == NULL) ? 1 : 0);
6149 layp = NULL;
6150 }
6151 /* Try and get a Layout, if it is supported. */
6152 if (rwaccess == NFSV4OPEN_ACCESSWRITE ||
6153 (np->n_flag & NWRITEOPENED) != 0)
6154 iolaymode = NFSLAYOUTIOMODE_RW;
6155 else
6156 iolaymode = NFSLAYOUTIOMODE_READ;
6157 error = nfsrpc_getlayout(nmp, vp, np->n_fhp, iolaymode,
6158 rwaccess, NULL, &stateid, off, &layp, newcred, p);
6159 if (error != 0) {
6160 NFSLOCKNODE(np);
6161 np->n_flag |= NNOLAYOUT;
6162 NFSUNLOCKNODE(np);
6163 if (lckp != NULL)
6164 nfscl_lockderef(lckp);
6165 NFSFREECRED(newcred);
6166 if (layp != NULL)
6167 nfscl_rellayout(layp, 0);
6168 nfscl_relref(nmp);
6169 return (error);
6170 }
6171 }
6172
6173 /*
6174 * Loop around finding a layout that works for the first part of
6175 * this I/O operation, and then call the function that actually
6176 * does the RPC.
6177 */
6178 eof = 0;
6179 len = (uint64_t)uiop->uio_resid;
6180 while (len > 0 && error == 0 && eof == 0) {
6181 off = uiop->uio_offset;
6182 error = nfscl_findlayoutforio(layp, off, rwaccess, &rflp);
6183 if (error == 0) {
6184 oresid = xfer = (uint64_t)uiop->uio_resid;
6185 if (xfer > (rflp->nfsfl_end - rflp->nfsfl_off))
6186 xfer = rflp->nfsfl_end - rflp->nfsfl_off;
6187 /*
6188 * For Flex File layout with mirrored DSs, select one
6189 * of them at random for reads. For writes and commits,
6190 * do all mirrors.
6191 */
6192 m = NULL;
6193 tdrpc = drpc = NULL;
6194 firstmirror = 0;
6195 mirrorcnt = 1;
6196 if ((layp->nfsly_flags & NFSLY_FLEXFILE) != 0 &&
6197 (mirrorcnt = rflp->nfsfl_mirrorcnt) > 1) {
6198 if (rwaccess == NFSV4OPEN_ACCESSREAD) {
6199 firstmirror = arc4random() % mirrorcnt;
6200 mirrorcnt = firstmirror + 1;
6201 } else {
6202 if (docommit == 0) {
6203 /*
6204 * Save values, so uiop can be
6205 * rolled back upon a write
6206 * error.
6207 */
6208 offs = uiop->uio_offset;
6209 resid = uiop->uio_resid;
6210 iovbase =
6211 uiop->uio_iov->iov_base;
6212 iovlen = uiop->uio_iov->iov_len;
6213 m = nfsm_uiombuflist(uiop, len,
6214 0);
6215 }
6216 tdrpc = drpc = malloc(sizeof(*drpc) *
6217 (mirrorcnt - 1), M_TEMP, M_WAITOK |
6218 M_ZERO);
6219 }
6220 }
6221 for (i = firstmirror; i < mirrorcnt && error == 0; i++){
6222 m2 = NULL;
6223 if (m != NULL && i < mirrorcnt - 1)
6224 m2 = m_copym(m, 0, M_COPYALL, M_WAITOK);
6225 else {
6226 m2 = m;
6227 m = NULL;
6228 }
6229 if ((layp->nfsly_flags & NFSLY_FLEXFILE) != 0) {
6230 dev = rflp->nfsfl_ffm[i].dev;
6231 dip = nfscl_getdevinfo(nmp->nm_clp, dev,
6232 rflp->nfsfl_ffm[i].devp);
6233 } else {
6234 dev = rflp->nfsfl_dev;
6235 dip = nfscl_getdevinfo(nmp->nm_clp, dev,
6236 rflp->nfsfl_devp);
6237 }
6238 if (dip != NULL) {
6239 if ((rflp->nfsfl_flags & NFSFL_FLEXFILE)
6240 != 0)
6241 error = nfscl_dofflayoutio(vp,
6242 uiop, iomode, must_commit,
6243 &eof, &stateid, rwaccess,
6244 dip, layp, rflp, off, xfer,
6245 i, docommit, m2, tdrpc,
6246 newcred, p);
6247 else
6248 error = nfscl_doflayoutio(vp,
6249 uiop, iomode, must_commit,
6250 &eof, &stateid, rwaccess,
6251 dip, layp, rflp, off, xfer,
6252 docommit, newcred, p);
6253 nfscl_reldevinfo(dip);
6254 } else {
6255 if (m2 != NULL)
6256 m_freem(m2);
6257 error = EIO;
6258 }
6259 tdrpc++;
6260 }
6261 if (m != NULL)
6262 m_freem(m);
6263 tdrpc = drpc;
6264 timo = hz / 50; /* Wait for 20msec. */
6265 if (timo < 1)
6266 timo = 1;
6267 for (i = firstmirror; i < mirrorcnt - 1 &&
6268 tdrpc != NULL; i++, tdrpc++) {
6269 /*
6270 * For the unused drpc entries, both inprog and
6271 * err == 0, so this loop won't break.
6272 */
6273 while (tdrpc->inprog != 0 && tdrpc->done == 0)
6274 tsleep(&tdrpc->tsk, PVFS, "clrpcio",
6275 timo);
6276 if (error == 0 && tdrpc->err != 0)
6277 error = tdrpc->err;
6278 if (rwaccess != NFSV4OPEN_ACCESSREAD &&
6279 docommit == 0 && *must_commit == 0 &&
6280 tdrpc->must_commit == 1)
6281 *must_commit = 1;
6282 }
6283 free(drpc, M_TEMP);
6284 if (error == 0) {
6285 if (mirrorcnt > 1 && rwaccess ==
6286 NFSV4OPEN_ACCESSWRITE && docommit == 0) {
6287 NFSLOCKCLSTATE();
6288 layp->nfsly_flags |= NFSLY_WRITTEN;
6289 NFSUNLOCKCLSTATE();
6290 }
6291 lastbyte = off + xfer - 1;
6292 NFSLOCKCLSTATE();
6293 if (lastbyte > layp->nfsly_lastbyte)
6294 layp->nfsly_lastbyte = lastbyte;
6295 NFSUNLOCKCLSTATE();
6296 } else if (error == NFSERR_OPENMODE &&
6297 rwaccess == NFSV4OPEN_ACCESSREAD) {
6298 NFSLOCKMNT(nmp);
6299 nmp->nm_state |= NFSSTA_OPENMODE;
6300 NFSUNLOCKMNT(nmp);
6301 } else if ((error == NFSERR_NOSPC ||
6302 error == NFSERR_IO || error == NFSERR_NXIO) &&
6303 nmp->nm_minorvers == NFSV42_MINORVERSION) {
6304 if (docommit != 0)
6305 op = NFSV4OP_COMMIT;
6306 else if (rwaccess == NFSV4OPEN_ACCESSREAD)
6307 op = NFSV4OP_READ;
6308 else
6309 op = NFSV4OP_WRITE;
6310 nfsrpc_layouterror(nmp, np->n_fhp->nfh_fh,
6311 np->n_fhp->nfh_len, off, xfer,
6312 &layp->nfsly_stateid, newcred, p, error, op,
6313 dip->nfsdi_deviceid);
6314 error = EIO;
6315 } else
6316 error = EIO;
6317 if (error == 0)
6318 len -= (oresid - (uint64_t)uiop->uio_resid);
6319 else if (mirrorcnt > 1 && rwaccess ==
6320 NFSV4OPEN_ACCESSWRITE && docommit == 0) {
6321 /*
6322 * In case the rpc gets retried, roll the
6323 * uio fields changed by nfsm_uiombuflist()
6324 * back.
6325 */
6326 uiop->uio_offset = offs;
6327 uiop->uio_resid = resid;
6328 uiop->uio_iov->iov_base = iovbase;
6329 uiop->uio_iov->iov_len = iovlen;
6330 }
6331 }
6332 }
6333 if (lckp != NULL)
6334 nfscl_lockderef(lckp);
6335 NFSFREECRED(newcred);
6336 nfscl_rellayout(layp, 0);
6337 nfscl_relref(nmp);
6338 return (error);
6339 }
6340
6341 /*
6342 * Find a file layout that will handle the first bytes of the requested
6343 * range and return the information from it needed to the I/O operation.
6344 */
6345 int
6346 nfscl_findlayoutforio(struct nfscllayout *lyp, uint64_t off, uint32_t rwaccess,
6347 struct nfsclflayout **retflpp)
6348 {
6349 struct nfsclflayout *flp, *nflp, *rflp;
6350 uint32_t rw;
6351
6352 rflp = NULL;
6353 rw = rwaccess;
6354 /* For reading, do the Read list first and then the Write list. */
6355 do {
6356 if (rw == NFSV4OPEN_ACCESSREAD)
6357 flp = LIST_FIRST(&lyp->nfsly_flayread);
6358 else
6359 flp = LIST_FIRST(&lyp->nfsly_flayrw);
6360 while (flp != NULL) {
6361 nflp = LIST_NEXT(flp, nfsfl_list);
6362 if (flp->nfsfl_off > off)
6363 break;
6364 if (flp->nfsfl_end > off &&
6365 (rflp == NULL || rflp->nfsfl_end < flp->nfsfl_end))
6366 rflp = flp;
6367 flp = nflp;
6368 }
6369 if (rw == NFSV4OPEN_ACCESSREAD)
6370 rw = NFSV4OPEN_ACCESSWRITE;
6371 else
6372 rw = 0;
6373 } while (rw != 0);
6374 if (rflp != NULL) {
6375 /* This one covers the most bytes starting at off. */
6376 *retflpp = rflp;
6377 return (0);
6378 }
6379 return (EIO);
6380 }
6381
6382 /*
6383 * Do I/O using an NFSv4.1 or NFSv4.2 file layout.
6384 */
6385 static int
6386 nfscl_doflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
6387 int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp,
6388 struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off,
6389 uint64_t len, int docommit, struct ucred *cred, NFSPROC_T *p)
6390 {
6391 uint64_t io_off, rel_off, stripe_unit_size, transfer, xfer;
6392 int commit_thru_mds, error, stripe_index, stripe_pos, minorvers;
6393 struct nfsnode *np;
6394 struct nfsfh *fhp;
6395 struct nfsclds **dspp;
6396
6397 np = VTONFS(vp);
6398 rel_off = off - flp->nfsfl_patoff;
6399 stripe_unit_size = flp->nfsfl_util & NFSFLAYUTIL_STRIPE_MASK;
6400 stripe_pos = (rel_off / stripe_unit_size + flp->nfsfl_stripe1) %
6401 dp->nfsdi_stripecnt;
6402 transfer = stripe_unit_size - (rel_off % stripe_unit_size);
6403 error = 0;
6404
6405 /* Loop around, doing I/O for each stripe unit. */
6406 while (len > 0 && error == 0) {
6407 stripe_index = nfsfldi_stripeindex(dp, stripe_pos);
6408 dspp = nfsfldi_addr(dp, stripe_index);
6409 if (((*dspp)->nfsclds_flags & NFSCLDS_MINORV2) != 0)
6410 minorvers = NFSV42_MINORVERSION;
6411 else
6412 minorvers = NFSV41_MINORVERSION;
6413 if (len > transfer && docommit == 0)
6414 xfer = transfer;
6415 else
6416 xfer = len;
6417 if ((flp->nfsfl_util & NFSFLAYUTIL_DENSE) != 0) {
6418 /* Dense layout. */
6419 if (stripe_pos >= flp->nfsfl_fhcnt)
6420 return (EIO);
6421 fhp = flp->nfsfl_fh[stripe_pos];
6422 io_off = (rel_off / (stripe_unit_size *
6423 dp->nfsdi_stripecnt)) * stripe_unit_size +
6424 rel_off % stripe_unit_size;
6425 } else {
6426 /* Sparse layout. */
6427 if (flp->nfsfl_fhcnt > 1) {
6428 if (stripe_index >= flp->nfsfl_fhcnt)
6429 return (EIO);
6430 fhp = flp->nfsfl_fh[stripe_index];
6431 } else if (flp->nfsfl_fhcnt == 1)
6432 fhp = flp->nfsfl_fh[0];
6433 else
6434 fhp = np->n_fhp;
6435 io_off = off;
6436 }
6437 if ((flp->nfsfl_util & NFSFLAYUTIL_COMMIT_THRU_MDS) != 0) {
6438 commit_thru_mds = 1;
6439 if (docommit != 0)
6440 error = EIO;
6441 } else {
6442 commit_thru_mds = 0;
6443 NFSLOCKNODE(np);
6444 np->n_flag |= NDSCOMMIT;
6445 NFSUNLOCKNODE(np);
6446 }
6447 if (docommit != 0) {
6448 if (error == 0)
6449 error = nfsrpc_commitds(vp, io_off, xfer,
6450 *dspp, fhp, NFS_VER4, minorvers, cred, p);
6451 if (error == 0) {
6452 /*
6453 * Set both eof and uio_resid = 0 to end any
6454 * loops.
6455 */
6456 *eofp = 1;
6457 uiop->uio_resid = 0;
6458 } else {
6459 NFSLOCKNODE(np);
6460 np->n_flag &= ~NDSCOMMIT;
6461 NFSUNLOCKNODE(np);
6462 }
6463 } else if (rwflag == NFSV4OPEN_ACCESSREAD)
6464 error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp,
6465 io_off, xfer, fhp, 0, NFS_VER4, minorvers, cred, p);
6466 else {
6467 error = nfsrpc_writeds(vp, uiop, iomode, must_commit,
6468 stateidp, *dspp, io_off, xfer, fhp, commit_thru_mds,
6469 0, NFS_VER4, minorvers, cred, p);
6470 if (error == 0) {
6471 NFSLOCKCLSTATE();
6472 lyp->nfsly_flags |= NFSLY_WRITTEN;
6473 NFSUNLOCKCLSTATE();
6474 }
6475 }
6476 if (error == 0) {
6477 transfer = stripe_unit_size;
6478 stripe_pos = (stripe_pos + 1) % dp->nfsdi_stripecnt;
6479 len -= xfer;
6480 off += xfer;
6481 }
6482 }
6483 return (error);
6484 }
6485
6486 /*
6487 * Do I/O using an NFSv4.1 flex file layout.
6488 */
6489 static int
6490 nfscl_dofflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
6491 int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp,
6492 struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off,
6493 uint64_t len, int mirror, int docommit, struct mbuf *mp,
6494 struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p)
6495 {
6496 uint64_t xfer;
6497 int error;
6498 struct nfsnode *np;
6499 struct nfsfh *fhp;
6500 struct nfsclds **dspp;
6501 struct ucred *tcred;
6502 struct mbuf *m, *m2;
6503 uint32_t copylen;
6504
6505 np = VTONFS(vp);
6506 error = 0;
6507 NFSCL_DEBUG(4, "nfscl_dofflayoutio: off=%ju len=%ju\n", (uintmax_t)off,
6508 (uintmax_t)len);
6509 /* Loop around, doing I/O for each stripe unit. */
6510 while (len > 0 && error == 0) {
6511 dspp = nfsfldi_addr(dp, 0);
6512 fhp = flp->nfsfl_ffm[mirror].fh[dp->nfsdi_versindex];
6513 stateidp = &flp->nfsfl_ffm[mirror].st;
6514 NFSCL_DEBUG(4, "mirror=%d vind=%d fhlen=%d st.seqid=0x%x\n",
6515 mirror, dp->nfsdi_versindex, fhp->nfh_len, stateidp->seqid);
6516 if ((dp->nfsdi_flags & NFSDI_TIGHTCOUPLED) == 0) {
6517 tcred = NFSNEWCRED(cred);
6518 tcred->cr_uid = flp->nfsfl_ffm[mirror].user;
6519 tcred->cr_groups[0] = flp->nfsfl_ffm[mirror].group;
6520 tcred->cr_ngroups = 1;
6521 } else
6522 tcred = cred;
6523 if (rwflag == NFSV4OPEN_ACCESSREAD)
6524 copylen = dp->nfsdi_rsize;
6525 else {
6526 copylen = dp->nfsdi_wsize;
6527 if (len > copylen && mp != NULL) {
6528 /*
6529 * When a mirrored configuration needs to do
6530 * multiple writes to each mirror, all writes
6531 * except the last one must be a multiple of
6532 * 4 bytes. This is required so that the XDR
6533 * does not need padding.
6534 * If possible, clip the size to an exact
6535 * multiple of the mbuf length, so that the
6536 * split will be on an mbuf boundary.
6537 */
6538 copylen &= 0xfffffffc;
6539 if (copylen > mp->m_len)
6540 copylen = copylen / mp->m_len *
6541 mp->m_len;
6542 }
6543 }
6544 NFSLOCKNODE(np);
6545 np->n_flag |= NDSCOMMIT;
6546 NFSUNLOCKNODE(np);
6547 if (len > copylen && docommit == 0)
6548 xfer = copylen;
6549 else
6550 xfer = len;
6551 if (docommit != 0) {
6552 if (error == 0) {
6553 /*
6554 * Do last mirrored DS commit with this thread.
6555 */
6556 if (mirror < flp->nfsfl_mirrorcnt - 1)
6557 error = nfsio_commitds(vp, off, xfer,
6558 *dspp, fhp, dp->nfsdi_vers,
6559 dp->nfsdi_minorvers, drpc, tcred,
6560 p);
6561 else
6562 error = nfsrpc_commitds(vp, off, xfer,
6563 *dspp, fhp, dp->nfsdi_vers,
6564 dp->nfsdi_minorvers, tcred, p);
6565 NFSCL_DEBUG(4, "commitds=%d\n", error);
6566 if (error != 0 && error != EACCES && error !=
6567 ESTALE) {
6568 NFSCL_DEBUG(4,
6569 "DS layreterr for commit\n");
6570 nfscl_dserr(NFSV4OP_COMMIT, error, dp,
6571 lyp, *dspp);
6572 }
6573 }
6574 NFSCL_DEBUG(4, "aft nfsio_commitds=%d\n", error);
6575 if (error == 0) {
6576 /*
6577 * Set both eof and uio_resid = 0 to end any
6578 * loops.
6579 */
6580 *eofp = 1;
6581 uiop->uio_resid = 0;
6582 } else {
6583 NFSLOCKNODE(np);
6584 np->n_flag &= ~NDSCOMMIT;
6585 NFSUNLOCKNODE(np);
6586 }
6587 } else if (rwflag == NFSV4OPEN_ACCESSREAD) {
6588 error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp,
6589 off, xfer, fhp, 1, dp->nfsdi_vers,
6590 dp->nfsdi_minorvers, tcred, p);
6591 NFSCL_DEBUG(4, "readds=%d\n", error);
6592 if (error != 0 && error != EACCES && error != ESTALE) {
6593 NFSCL_DEBUG(4, "DS layreterr for read\n");
6594 nfscl_dserr(NFSV4OP_READ, error, dp, lyp,
6595 *dspp);
6596 }
6597 } else {
6598 if (flp->nfsfl_mirrorcnt == 1) {
6599 error = nfsrpc_writeds(vp, uiop, iomode,
6600 must_commit, stateidp, *dspp, off, xfer,
6601 fhp, 0, 1, dp->nfsdi_vers,
6602 dp->nfsdi_minorvers, tcred, p);
6603 if (error == 0) {
6604 NFSLOCKCLSTATE();
6605 lyp->nfsly_flags |= NFSLY_WRITTEN;
6606 NFSUNLOCKCLSTATE();
6607 }
6608 } else {
6609 m = mp;
6610 if (xfer < len) {
6611 /* The mbuf list must be split. */
6612 m2 = nfsm_split(mp, xfer);
6613 if (m2 != NULL)
6614 mp = m2;
6615 else {
6616 m_freem(mp);
6617 error = EIO;
6618 }
6619 }
6620 NFSCL_DEBUG(4, "mcopy len=%jd xfer=%jd\n",
6621 (uintmax_t)len, (uintmax_t)xfer);
6622 /*
6623 * Do last write to a mirrored DS with this
6624 * thread.
6625 */
6626 if (error == 0) {
6627 if (mirror < flp->nfsfl_mirrorcnt - 1)
6628 error = nfsio_writedsmir(vp,
6629 iomode, must_commit,
6630 stateidp, *dspp, off,
6631 xfer, fhp, m,
6632 dp->nfsdi_vers,
6633 dp->nfsdi_minorvers, drpc,
6634 tcred, p);
6635 else
6636 error = nfsrpc_writedsmir(vp,
6637 iomode, must_commit,
6638 stateidp, *dspp, off,
6639 xfer, fhp, m,
6640 dp->nfsdi_vers,
6641 dp->nfsdi_minorvers, tcred,
6642 p);
6643 }
6644 NFSCL_DEBUG(4, "nfsio_writedsmir=%d\n", error);
6645 if (error != 0 && error != EACCES && error !=
6646 ESTALE) {
6647 NFSCL_DEBUG(4,
6648 "DS layreterr for write\n");
6649 nfscl_dserr(NFSV4OP_WRITE, error, dp,
6650 lyp, *dspp);
6651 }
6652 }
6653 }
6654 NFSCL_DEBUG(4, "aft read/writeds=%d\n", error);
6655 if (error == 0) {
6656 len -= xfer;
6657 off += xfer;
6658 }
6659 if ((dp->nfsdi_flags & NFSDI_TIGHTCOUPLED) == 0)
6660 NFSFREECRED(tcred);
6661 }
6662 NFSCL_DEBUG(4, "eo nfscl_dofflayoutio=%d\n", error);
6663 return (error);
6664 }
6665
6666 /*
6667 * The actual read RPC done to a DS.
6668 */
6669 static int
6670 nfsrpc_readds(vnode_t vp, struct uio *uiop, nfsv4stateid_t *stateidp, int *eofp,
6671 struct nfsclds *dsp, uint64_t io_off, int len, struct nfsfh *fhp, int flex,
6672 int vers, int minorvers, struct ucred *cred, NFSPROC_T *p)
6673 {
6674 uint32_t *tl;
6675 int attrflag, error, retlen;
6676 struct nfsrv_descript nfsd;
6677 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
6678 struct nfsrv_descript *nd = &nfsd;
6679 struct nfssockreq *nrp;
6680 struct nfsvattr na;
6681
6682 nd->nd_mrep = NULL;
6683 if (vers == 0 || vers == NFS_VER4) {
6684 nfscl_reqstart(nd, NFSPROC_READDS, nmp, fhp->nfh_fh,
6685 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers,
6686 NULL);
6687 vers = NFS_VER4;
6688 NFSCL_DEBUG(4, "nfsrpc_readds: vers4 minvers=%d\n", minorvers);
6689 if (flex != 0)
6690 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
6691 else
6692 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO);
6693 } else {
6694 nfscl_reqstart(nd, NFSPROC_READ, nmp, fhp->nfh_fh,
6695 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers,
6696 NULL);
6697 NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_READ]);
6698 NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_READDS]);
6699 NFSCL_DEBUG(4, "nfsrpc_readds: vers3\n");
6700 }
6701 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED * 3);
6702 txdr_hyper(io_off, tl);
6703 *(tl + 2) = txdr_unsigned(len);
6704 nrp = dsp->nfsclds_sockp;
6705 NFSCL_DEBUG(4, "nfsrpc_readds: nrp=%p\n", nrp);
6706 if (nrp == NULL)
6707 /* If NULL, use the MDS socket. */
6708 nrp = &nmp->nm_sockreq;
6709 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
6710 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess);
6711 NFSCL_DEBUG(4, "nfsrpc_readds: stat=%d err=%d\n", nd->nd_repstat,
6712 error);
6713 if (error != 0)
6714 return (error);
6715 if (vers == NFS_VER3) {
6716 error = nfscl_postop_attr(nd, &na, &attrflag);
6717 NFSCL_DEBUG(4, "nfsrpc_readds: postop=%d\n", error);
6718 if (error != 0)
6719 goto nfsmout;
6720 }
6721 if (nd->nd_repstat != 0) {
6722 error = nd->nd_repstat;
6723 goto nfsmout;
6724 }
6725 if (vers == NFS_VER3) {
6726 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
6727 *eofp = fxdr_unsigned(int, *(tl + 1));
6728 } else {
6729 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
6730 *eofp = fxdr_unsigned(int, *tl);
6731 }
6732 NFSM_STRSIZ(retlen, len);
6733 NFSCL_DEBUG(4, "nfsrpc_readds: retlen=%d eof=%d\n", retlen, *eofp);
6734 error = nfsm_mbufuio(nd, uiop, retlen);
6735 nfsmout:
6736 if (nd->nd_mrep != NULL)
6737 m_freem(nd->nd_mrep);
6738 return (error);
6739 }
6740
6741 /*
6742 * The actual write RPC done to a DS.
6743 */
6744 static int
6745 nfsrpc_writeds(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
6746 nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len,
6747 struct nfsfh *fhp, int commit_thru_mds, int flex, int vers, int minorvers,
6748 struct ucred *cred, NFSPROC_T *p)
6749 {
6750 uint32_t *tl;
6751 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
6752 int attrflag, error, rlen, commit, committed = NFSWRITE_FILESYNC;
6753 int32_t backup;
6754 struct nfsrv_descript nfsd;
6755 struct nfsrv_descript *nd = &nfsd;
6756 struct nfssockreq *nrp;
6757 struct nfsvattr na;
6758
6759 KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1"));
6760 nd->nd_mrep = NULL;
6761 if (vers == 0 || vers == NFS_VER4) {
6762 nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh,
6763 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers,
6764 NULL);
6765 NFSCL_DEBUG(4, "nfsrpc_writeds: vers4 minvers=%d\n", minorvers);
6766 vers = NFS_VER4;
6767 if (flex != 0)
6768 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
6769 else
6770 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO);
6771 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
6772 } else {
6773 nfscl_reqstart(nd, NFSPROC_WRITE, nmp, fhp->nfh_fh,
6774 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers,
6775 NULL);
6776 NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITE]);
6777 NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITEDS]);
6778 NFSCL_DEBUG(4, "nfsrpc_writeds: vers3\n");
6779 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED);
6780 }
6781 txdr_hyper(io_off, tl);
6782 tl += 2;
6783 if (vers == NFS_VER3)
6784 *tl++ = txdr_unsigned(len);
6785 *tl++ = txdr_unsigned(*iomode);
6786 *tl = txdr_unsigned(len);
6787 nfsm_uiombuf(nd, uiop, len);
6788 nrp = dsp->nfsclds_sockp;
6789 if (nrp == NULL)
6790 /* If NULL, use the MDS socket. */
6791 nrp = &nmp->nm_sockreq;
6792 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
6793 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess);
6794 NFSCL_DEBUG(4, "nfsrpc_writeds: err=%d stat=%d\n", error,
6795 nd->nd_repstat);
6796 if (error != 0)
6797 return (error);
6798 if (nd->nd_repstat != 0) {
6799 /*
6800 * In case the rpc gets retried, roll
6801 * the uio fields changed by nfsm_uiombuf()
6802 * back.
6803 */
6804 uiop->uio_offset -= len;
6805 uiop->uio_resid += len;
6806 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base - len;
6807 uiop->uio_iov->iov_len += len;
6808 error = nd->nd_repstat;
6809 } else {
6810 if (vers == NFS_VER3) {
6811 error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL,
6812 NULL);
6813 NFSCL_DEBUG(4, "nfsrpc_writeds: wcc_data=%d\n", error);
6814 if (error != 0)
6815 goto nfsmout;
6816 }
6817 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF);
6818 rlen = fxdr_unsigned(int, *tl++);
6819 NFSCL_DEBUG(4, "nfsrpc_writeds: len=%d rlen=%d\n", len, rlen);
6820 if (rlen == 0) {
6821 error = NFSERR_IO;
6822 goto nfsmout;
6823 } else if (rlen < len) {
6824 backup = len - rlen;
6825 uiop->uio_iov->iov_base =
6826 (char *)uiop->uio_iov->iov_base - backup;
6827 uiop->uio_iov->iov_len += backup;
6828 uiop->uio_offset -= backup;
6829 uiop->uio_resid += backup;
6830 len = rlen;
6831 }
6832 commit = fxdr_unsigned(int, *tl++);
6833
6834 /*
6835 * Return the lowest commitment level
6836 * obtained by any of the RPCs.
6837 */
6838 if (committed == NFSWRITE_FILESYNC)
6839 committed = commit;
6840 else if (committed == NFSWRITE_DATASYNC &&
6841 commit == NFSWRITE_UNSTABLE)
6842 committed = commit;
6843 if (commit_thru_mds != 0) {
6844 NFSLOCKMNT(nmp);
6845 if (!NFSHASWRITEVERF(nmp)) {
6846 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
6847 NFSSETWRITEVERF(nmp);
6848 } else if (NFSBCMP(tl, nmp->nm_verf, NFSX_VERF) &&
6849 *must_commit != 2) {
6850 *must_commit = 1;
6851 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
6852 }
6853 NFSUNLOCKMNT(nmp);
6854 } else {
6855 NFSLOCKDS(dsp);
6856 if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) {
6857 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
6858 dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF;
6859 } else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF) &&
6860 *must_commit != 2) {
6861 *must_commit = 1;
6862 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
6863 }
6864 NFSUNLOCKDS(dsp);
6865 }
6866 }
6867 nfsmout:
6868 if (nd->nd_mrep != NULL)
6869 m_freem(nd->nd_mrep);
6870 *iomode = committed;
6871 if (nd->nd_repstat != 0 && error == 0)
6872 error = nd->nd_repstat;
6873 return (error);
6874 }
6875
6876 /*
6877 * The actual write RPC done to a DS.
6878 * This variant is called from a separate kernel process for mirrors.
6879 * Any short write is considered an IO error.
6880 */
6881 static int
6882 nfsrpc_writedsmir(vnode_t vp, int *iomode, int *must_commit,
6883 nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len,
6884 struct nfsfh *fhp, struct mbuf *m, int vers, int minorvers,
6885 struct ucred *cred, NFSPROC_T *p)
6886 {
6887 uint32_t *tl;
6888 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
6889 int attrflag, error, commit, committed = NFSWRITE_FILESYNC, rlen;
6890 struct nfsrv_descript nfsd;
6891 struct nfsrv_descript *nd = &nfsd;
6892 struct nfssockreq *nrp;
6893 struct nfsvattr na;
6894
6895 nd->nd_mrep = NULL;
6896 if (vers == 0 || vers == NFS_VER4) {
6897 nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh,
6898 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers,
6899 NULL);
6900 vers = NFS_VER4;
6901 NFSCL_DEBUG(4, "nfsrpc_writedsmir: vers4 minvers=%d\n",
6902 minorvers);
6903 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
6904 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
6905 } else {
6906 nfscl_reqstart(nd, NFSPROC_WRITE, nmp, fhp->nfh_fh,
6907 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers,
6908 NULL);
6909 NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITE]);
6910 NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITEDS]);
6911 NFSCL_DEBUG(4, "nfsrpc_writedsmir: vers3\n");
6912 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED);
6913 }
6914 txdr_hyper(io_off, tl);
6915 tl += 2;
6916 if (vers == NFS_VER3)
6917 *tl++ = txdr_unsigned(len);
6918 *tl++ = txdr_unsigned(*iomode);
6919 *tl = txdr_unsigned(len);
6920 if (len > 0) {
6921 /* Put data in mbuf chain. */
6922 nd->nd_mb->m_next = m;
6923 }
6924 nrp = dsp->nfsclds_sockp;
6925 if (nrp == NULL)
6926 /* If NULL, use the MDS socket. */
6927 nrp = &nmp->nm_sockreq;
6928 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
6929 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess);
6930 NFSCL_DEBUG(4, "nfsrpc_writedsmir: err=%d stat=%d\n", error,
6931 nd->nd_repstat);
6932 if (error != 0)
6933 return (error);
6934 if (nd->nd_repstat != 0)
6935 error = nd->nd_repstat;
6936 else {
6937 if (vers == NFS_VER3) {
6938 error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL,
6939 NULL);
6940 NFSCL_DEBUG(4, "nfsrpc_writedsmir: wcc_data=%d\n",
6941 error);
6942 if (error != 0)
6943 goto nfsmout;
6944 }
6945 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF);
6946 rlen = fxdr_unsigned(int, *tl++);
6947 NFSCL_DEBUG(4, "nfsrpc_writedsmir: len=%d rlen=%d\n", len,
6948 rlen);
6949 if (rlen != len) {
6950 error = NFSERR_IO;
6951 NFSCL_DEBUG(4, "nfsrpc_writedsmir: len=%d rlen=%d\n",
6952 len, rlen);
6953 goto nfsmout;
6954 }
6955 commit = fxdr_unsigned(int, *tl++);
6956
6957 /*
6958 * Return the lowest commitment level
6959 * obtained by any of the RPCs.
6960 */
6961 if (committed == NFSWRITE_FILESYNC)
6962 committed = commit;
6963 else if (committed == NFSWRITE_DATASYNC &&
6964 commit == NFSWRITE_UNSTABLE)
6965 committed = commit;
6966 NFSLOCKDS(dsp);
6967 if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) {
6968 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
6969 dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF;
6970 } else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF) &&
6971 *must_commit != 2) {
6972 *must_commit = 1;
6973 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
6974 }
6975 NFSUNLOCKDS(dsp);
6976 }
6977 nfsmout:
6978 if (nd->nd_mrep != NULL)
6979 m_freem(nd->nd_mrep);
6980 *iomode = committed;
6981 if (nd->nd_repstat != 0 && error == 0)
6982 error = nd->nd_repstat;
6983 return (error);
6984 }
6985
6986 /*
6987 * Start up the thread that will execute nfsrpc_writedsmir().
6988 */
6989 static void
6990 start_writedsmir(void *arg, int pending)
6991 {
6992 struct nfsclwritedsdorpc *drpc;
6993
6994 drpc = (struct nfsclwritedsdorpc *)arg;
6995 drpc->err = nfsrpc_writedsmir(drpc->vp, &drpc->iomode,
6996 &drpc->must_commit, drpc->stateidp, drpc->dsp, drpc->off, drpc->len,
6997 drpc->fhp, drpc->m, drpc->vers, drpc->minorvers, drpc->cred,
6998 drpc->p);
6999 drpc->done = 1;
7000 crfree(drpc->cred);
7001 NFSCL_DEBUG(4, "start_writedsmir: err=%d\n", drpc->err);
7002 }
7003
7004 /*
7005 * Set up the write DS mirror call for the pNFS I/O thread.
7006 */
7007 static int
7008 nfsio_writedsmir(vnode_t vp, int *iomode, int *must_commit,
7009 nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t off, int len,
7010 struct nfsfh *fhp, struct mbuf *m, int vers, int minorvers,
7011 struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p)
7012 {
7013 int error, ret;
7014
7015 error = 0;
7016 drpc->done = 0;
7017 drpc->vp = vp;
7018 drpc->iomode = *iomode;
7019 drpc->must_commit = *must_commit;
7020 drpc->stateidp = stateidp;
7021 drpc->dsp = dsp;
7022 drpc->off = off;
7023 drpc->len = len;
7024 drpc->fhp = fhp;
7025 drpc->m = m;
7026 drpc->vers = vers;
7027 drpc->minorvers = minorvers;
7028 drpc->cred = crhold(cred);
7029 drpc->p = p;
7030 drpc->inprog = 0;
7031 ret = EIO;
7032 if (nfs_pnfsiothreads != 0) {
7033 ret = nfs_pnfsio(start_writedsmir, drpc);
7034 NFSCL_DEBUG(4, "nfsio_writedsmir: nfs_pnfsio=%d\n", ret);
7035 }
7036 if (ret != 0) {
7037 error = nfsrpc_writedsmir(vp, iomode, &drpc->must_commit,
7038 stateidp, dsp, off, len, fhp, m, vers, minorvers, cred, p);
7039 crfree(drpc->cred);
7040 }
7041 NFSCL_DEBUG(4, "nfsio_writedsmir: error=%d\n", error);
7042 return (error);
7043 }
7044
7045 /*
7046 * Free up the nfsclds structure.
7047 */
7048 void
7049 nfscl_freenfsclds(struct nfsclds *dsp)
7050 {
7051 int i;
7052
7053 if (dsp == NULL)
7054 return;
7055 if (dsp->nfsclds_sockp != NULL) {
7056 NFSFREECRED(dsp->nfsclds_sockp->nr_cred);
7057 NFSFREEMUTEX(&dsp->nfsclds_sockp->nr_mtx);
7058 free(dsp->nfsclds_sockp->nr_nam, M_SONAME);
7059 free(dsp->nfsclds_sockp, M_NFSSOCKREQ);
7060 }
7061 NFSFREEMUTEX(&dsp->nfsclds_mtx);
7062 NFSFREEMUTEX(&dsp->nfsclds_sess.nfsess_mtx);
7063 for (i = 0; i < NFSV4_CBSLOTS; i++) {
7064 if (dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply != NULL)
7065 m_freem(
7066 dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply);
7067 }
7068 free(dsp, M_NFSCLDS);
7069 }
7070
7071 static enum nfsclds_state
7072 nfscl_getsameserver(struct nfsmount *nmp, struct nfsclds *newdsp,
7073 struct nfsclds **retdspp, uint32_t *sequencep)
7074 {
7075 struct nfsclds *dsp;
7076 int fndseq;
7077
7078 /*
7079 * Search the list of nfsclds structures for one with the same
7080 * server.
7081 */
7082 fndseq = 0;
7083 TAILQ_FOREACH(dsp, &nmp->nm_sess, nfsclds_list) {
7084 if (dsp->nfsclds_servownlen == newdsp->nfsclds_servownlen &&
7085 dsp->nfsclds_servownlen != 0 &&
7086 !NFSBCMP(dsp->nfsclds_serverown, newdsp->nfsclds_serverown,
7087 dsp->nfsclds_servownlen) &&
7088 dsp->nfsclds_sess.nfsess_defunct == 0) {
7089 NFSCL_DEBUG(4, "fnd same fdsp=%p dsp=%p flg=0x%x\n",
7090 TAILQ_FIRST(&nmp->nm_sess), dsp,
7091 dsp->nfsclds_flags);
7092 if (fndseq == 0) {
7093 /* Get sequenceid# from first entry. */
7094 *sequencep =
7095 dsp->nfsclds_sess.nfsess_sequenceid;
7096 fndseq = 1;
7097 }
7098 /* Server major id matches. */
7099 if ((dsp->nfsclds_flags & NFSCLDS_DS) != 0) {
7100 *retdspp = dsp;
7101 return (NFSDSP_USETHISSESSION);
7102 }
7103 }
7104 }
7105 if (fndseq != 0)
7106 return (NFSDSP_SEQTHISSESSION);
7107 return (NFSDSP_NOTFOUND);
7108 }
7109
7110 /*
7111 * NFS commit rpc to a NFSv4.1 DS.
7112 */
7113 static int
7114 nfsrpc_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp,
7115 struct nfsfh *fhp, int vers, int minorvers, struct ucred *cred,
7116 NFSPROC_T *p)
7117 {
7118 uint32_t *tl;
7119 struct nfsrv_descript nfsd, *nd = &nfsd;
7120 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
7121 struct nfssockreq *nrp;
7122 struct nfsvattr na;
7123 int attrflag, error;
7124
7125 nd->nd_mrep = NULL;
7126 if (vers == 0 || vers == NFS_VER4) {
7127 nfscl_reqstart(nd, NFSPROC_COMMITDS, nmp, fhp->nfh_fh,
7128 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers,
7129 NULL);
7130 vers = NFS_VER4;
7131 } else {
7132 nfscl_reqstart(nd, NFSPROC_COMMIT, nmp, fhp->nfh_fh,
7133 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers,
7134 NULL);
7135 NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_COMMIT]);
7136 NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_COMMITDS]);
7137 }
7138 NFSCL_DEBUG(4, "nfsrpc_commitds: vers=%d minvers=%d\n", vers,
7139 minorvers);
7140 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
7141 txdr_hyper(offset, tl);
7142 tl += 2;
7143 *tl = txdr_unsigned(cnt);
7144 nrp = dsp->nfsclds_sockp;
7145 if (nrp == NULL)
7146 /* If NULL, use the MDS socket. */
7147 nrp = &nmp->nm_sockreq;
7148 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
7149 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess);
7150 NFSCL_DEBUG(4, "nfsrpc_commitds: err=%d stat=%d\n", error,
7151 nd->nd_repstat);
7152 if (error != 0)
7153 return (error);
7154 if (nd->nd_repstat == 0) {
7155 if (vers == NFS_VER3) {
7156 error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL,
7157 NULL);
7158 NFSCL_DEBUG(4, "nfsrpc_commitds: wccdata=%d\n", error);
7159 if (error != 0)
7160 goto nfsmout;
7161 }
7162 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
7163 NFSLOCKDS(dsp);
7164 if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) {
7165 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
7166 error = NFSERR_STALEWRITEVERF;
7167 }
7168 NFSUNLOCKDS(dsp);
7169 }
7170 nfsmout:
7171 if (error == 0 && nd->nd_repstat != 0)
7172 error = nd->nd_repstat;
7173 m_freem(nd->nd_mrep);
7174 return (error);
7175 }
7176
7177 /*
7178 * Start up the thread that will execute nfsrpc_commitds().
7179 */
7180 static void
7181 start_commitds(void *arg, int pending)
7182 {
7183 struct nfsclwritedsdorpc *drpc;
7184
7185 drpc = (struct nfsclwritedsdorpc *)arg;
7186 drpc->err = nfsrpc_commitds(drpc->vp, drpc->off, drpc->len,
7187 drpc->dsp, drpc->fhp, drpc->vers, drpc->minorvers, drpc->cred,
7188 drpc->p);
7189 drpc->done = 1;
7190 crfree(drpc->cred);
7191 NFSCL_DEBUG(4, "start_commitds: err=%d\n", drpc->err);
7192 }
7193
7194 /*
7195 * Set up the commit DS mirror call for the pNFS I/O thread.
7196 */
7197 static int
7198 nfsio_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp,
7199 struct nfsfh *fhp, int vers, int minorvers,
7200 struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p)
7201 {
7202 int error, ret;
7203
7204 error = 0;
7205 drpc->done = 0;
7206 drpc->vp = vp;
7207 drpc->off = offset;
7208 drpc->len = cnt;
7209 drpc->dsp = dsp;
7210 drpc->fhp = fhp;
7211 drpc->vers = vers;
7212 drpc->minorvers = minorvers;
7213 drpc->cred = crhold(cred);
7214 drpc->p = p;
7215 drpc->inprog = 0;
7216 ret = EIO;
7217 if (nfs_pnfsiothreads != 0) {
7218 ret = nfs_pnfsio(start_commitds, drpc);
7219 NFSCL_DEBUG(4, "nfsio_commitds: nfs_pnfsio=%d\n", ret);
7220 }
7221 if (ret != 0) {
7222 error = nfsrpc_commitds(vp, offset, cnt, dsp, fhp, vers,
7223 minorvers, cred, p);
7224 crfree(drpc->cred);
7225 }
7226 NFSCL_DEBUG(4, "nfsio_commitds: error=%d\n", error);
7227 return (error);
7228 }
7229
7230 /*
7231 * NFS Advise rpc
7232 */
7233 int
7234 nfsrpc_advise(vnode_t vp, off_t offset, uint64_t cnt, int advise,
7235 struct ucred *cred, NFSPROC_T *p)
7236 {
7237 u_int32_t *tl;
7238 struct nfsrv_descript nfsd, *nd = &nfsd;
7239 nfsattrbit_t hints;
7240 int error;
7241
7242 NFSZERO_ATTRBIT(&hints);
7243 if (advise == POSIX_FADV_WILLNEED)
7244 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED);
7245 else if (advise == POSIX_FADV_DONTNEED)
7246 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED);
7247 else
7248 return (0);
7249 NFSCL_REQSTART(nd, NFSPROC_IOADVISE, vp, cred);
7250 nfsm_stateidtom(nd, NULL, NFSSTATEID_PUTALLZERO);
7251 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER);
7252 txdr_hyper(offset, tl);
7253 tl += 2;
7254 txdr_hyper(cnt, tl);
7255 nfsrv_putattrbit(nd, &hints);
7256 error = nfscl_request(nd, vp, p, cred);
7257 if (error != 0)
7258 return (error);
7259 if (nd->nd_repstat != 0)
7260 error = nd->nd_repstat;
7261 m_freem(nd->nd_mrep);
7262 return (error);
7263 }
7264
7265 #ifdef notyet
7266 /*
7267 * NFS advise rpc to a NFSv4.2 DS.
7268 */
7269 static int
7270 nfsrpc_adviseds(vnode_t vp, uint64_t offset, int cnt, int advise,
7271 struct nfsclds *dsp, struct nfsfh *fhp, int vers, int minorvers,
7272 struct ucred *cred, NFSPROC_T *p)
7273 {
7274 uint32_t *tl;
7275 struct nfsrv_descript nfsd, *nd = &nfsd;
7276 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
7277 struct nfssockreq *nrp;
7278 nfsattrbit_t hints;
7279 int error;
7280
7281 /* For NFS DSs prior to NFSv4.2, just return OK. */
7282 if (vers == NFS_VER3 || minorversion < NFSV42_MINORVERSION)
7283 return (0);
7284 NFSZERO_ATTRBIT(&hints);
7285 if (advise == POSIX_FADV_WILLNEED)
7286 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED);
7287 else if (advise == POSIX_FADV_DONTNEED)
7288 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED);
7289 else
7290 return (0);
7291 nd->nd_mrep = NULL;
7292 nfscl_reqstart(nd, NFSPROC_IOADVISEDS, nmp, fhp->nfh_fh,
7293 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers, NULL);
7294 vers = NFS_VER4;
7295 NFSCL_DEBUG(4, "nfsrpc_adviseds: vers=%d minvers=%d\n", vers,
7296 minorvers);
7297 nfsm_stateidtom(nd, NULL, NFSSTATEID_PUTALLZERO);
7298 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
7299 txdr_hyper(offset, tl);
7300 tl += 2;
7301 *tl = txdr_unsigned(cnt);
7302 nfsrv_putattrbit(nd, &hints);
7303 nrp = dsp->nfsclds_sockp;
7304 if (nrp == NULL)
7305 /* If NULL, use the MDS socket. */
7306 nrp = &nmp->nm_sockreq;
7307 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
7308 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess);
7309 NFSCL_DEBUG(4, "nfsrpc_adviseds: err=%d stat=%d\n", error,
7310 nd->nd_repstat);
7311 if (error != 0)
7312 return (error);
7313 if (nd->nd_repstat != 0)
7314 error = nd->nd_repstat;
7315 m_freem(nd->nd_mrep);
7316 return (error);
7317 }
7318
7319 /*
7320 * Start up the thread that will execute nfsrpc_commitds().
7321 */
7322 static void
7323 start_adviseds(void *arg, int pending)
7324 {
7325 struct nfsclwritedsdorpc *drpc;
7326
7327 drpc = (struct nfsclwritedsdorpc *)arg;
7328 drpc->err = nfsrpc_adviseds(drpc->vp, drpc->off, drpc->len,
7329 drpc->advise, drpc->dsp, drpc->fhp, drpc->vers, drpc->minorvers,
7330 drpc->cred, drpc->p);
7331 drpc->done = 1;
7332 crfree(drpc->cred);
7333 NFSCL_DEBUG(4, "start_adviseds: err=%d\n", drpc->err);
7334 }
7335
7336 /*
7337 * Set up the advise DS mirror call for the pNFS I/O thread.
7338 */
7339 static int
7340 nfsio_adviseds(vnode_t vp, uint64_t offset, int cnt, int advise,
7341 struct nfsclds *dsp, struct nfsfh *fhp, int vers, int minorvers,
7342 struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p)
7343 {
7344 int error, ret;
7345
7346 error = 0;
7347 drpc->done = 0;
7348 drpc->vp = vp;
7349 drpc->off = offset;
7350 drpc->len = cnt;
7351 drpc->advise = advise;
7352 drpc->dsp = dsp;
7353 drpc->fhp = fhp;
7354 drpc->vers = vers;
7355 drpc->minorvers = minorvers;
7356 drpc->cred = crhold(cred);
7357 drpc->p = p;
7358 drpc->inprog = 0;
7359 ret = EIO;
7360 if (nfs_pnfsiothreads != 0) {
7361 ret = nfs_pnfsio(start_adviseds, drpc);
7362 NFSCL_DEBUG(4, "nfsio_adviseds: nfs_pnfsio=%d\n", ret);
7363 }
7364 if (ret != 0) {
7365 error = nfsrpc_adviseds(vp, offset, cnt, advise, dsp, fhp, vers,
7366 minorvers, cred, p);
7367 crfree(drpc->cred);
7368 }
7369 NFSCL_DEBUG(4, "nfsio_adviseds: error=%d\n", error);
7370 return (error);
7371 }
7372 #endif /* notyet */
7373
7374 /*
7375 * Do the Allocate operation, retrying for recovery.
7376 */
7377 int
7378 nfsrpc_allocate(vnode_t vp, off_t off, off_t len, struct nfsvattr *nap,
7379 int *attrflagp, struct ucred *cred, NFSPROC_T *p)
7380 {
7381 int error, expireret = 0, retrycnt, nostateid;
7382 uint32_t clidrev = 0;
7383 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
7384 struct nfsfh *nfhp = NULL;
7385 nfsv4stateid_t stateid;
7386 off_t tmp_off;
7387 void *lckp;
7388
7389 if (len < 0)
7390 return (EINVAL);
7391 if (len == 0)
7392 return (0);
7393 tmp_off = off + len;
7394 NFSLOCKMNT(nmp);
7395 if (tmp_off > nmp->nm_maxfilesize || tmp_off < off) {
7396 NFSUNLOCKMNT(nmp);
7397 return (EFBIG);
7398 }
7399 if (nmp->nm_clp != NULL)
7400 clidrev = nmp->nm_clp->nfsc_clientidrev;
7401 NFSUNLOCKMNT(nmp);
7402 nfhp = VTONFS(vp)->n_fhp;
7403 retrycnt = 0;
7404 do {
7405 lckp = NULL;
7406 nostateid = 0;
7407 nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
7408 NFSV4OPEN_ACCESSWRITE, 0, cred, p, &stateid, &lckp);
7409 if (stateid.other[0] == 0 && stateid.other[1] == 0 &&
7410 stateid.other[2] == 0) {
7411 nostateid = 1;
7412 NFSCL_DEBUG(1, "stateid0 in allocate\n");
7413 }
7414
7415 /*
7416 * Not finding a stateid should probably never happen,
7417 * but just return an error for this case.
7418 */
7419 if (nostateid != 0)
7420 error = EIO;
7421 else
7422 error = nfsrpc_allocaterpc(vp, off, len, &stateid,
7423 nap, attrflagp, cred, p);
7424 if (error == NFSERR_STALESTATEID)
7425 nfscl_initiate_recovery(nmp->nm_clp);
7426 if (lckp != NULL)
7427 nfscl_lockderef(lckp);
7428 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
7429 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
7430 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
7431 (void) nfs_catnap(PZERO, error, "nfs_allocate");
7432 } else if ((error == NFSERR_EXPIRED || (!NFSHASINT(nmp) &&
7433 error == NFSERR_BADSTATEID)) && clidrev != 0) {
7434 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
7435 } else if (error == NFSERR_BADSTATEID && NFSHASINT(nmp)) {
7436 error = EIO;
7437 }
7438 retrycnt++;
7439 } while (error == NFSERR_GRACE || error == NFSERR_DELAY ||
7440 error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION ||
7441 error == NFSERR_STALEDONTRECOVER ||
7442 (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
7443 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
7444 expireret == 0 && clidrev != 0 && retrycnt < 4));
7445 if (error != 0 && retrycnt >= 4)
7446 error = EIO;
7447 return (error);
7448 }
7449
7450 /*
7451 * The allocate RPC.
7452 */
7453 static int
7454 nfsrpc_allocaterpc(vnode_t vp, off_t off, off_t len, nfsv4stateid_t *stateidp,
7455 struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p)
7456 {
7457 uint32_t *tl;
7458 int error;
7459 struct nfsrv_descript nfsd;
7460 struct nfsrv_descript *nd = &nfsd;
7461 nfsattrbit_t attrbits;
7462
7463 *attrflagp = 0;
7464 NFSCL_REQSTART(nd, NFSPROC_ALLOCATE, vp, cred);
7465 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
7466 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED);
7467 txdr_hyper(off, tl); tl += 2;
7468 txdr_hyper(len, tl); tl += 2;
7469 *tl = txdr_unsigned(NFSV4OP_GETATTR);
7470 NFSGETATTR_ATTRBIT(&attrbits);
7471 nfsrv_putattrbit(nd, &attrbits);
7472 error = nfscl_request(nd, vp, p, cred);
7473 if (error != 0)
7474 return (error);
7475 if (nd->nd_repstat == 0) {
7476 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
7477 error = nfsm_loadattr(nd, nap);
7478 if (error == 0)
7479 *attrflagp = NFS_LATTR_NOSHRINK;
7480 } else
7481 error = nd->nd_repstat;
7482 nfsmout:
7483 m_freem(nd->nd_mrep);
7484 return (error);
7485 }
7486
7487 /*
7488 * Set up the XDR arguments for the LayoutGet operation.
7489 */
7490 static void
7491 nfsrv_setuplayoutget(struct nfsrv_descript *nd, int iomode, uint64_t offset,
7492 uint64_t len, uint64_t minlen, nfsv4stateid_t *stateidp, int layouttype,
7493 int layoutlen, int usecurstateid)
7494 {
7495 uint32_t *tl;
7496
7497 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
7498 NFSX_STATEID);
7499 *tl++ = newnfs_false; /* Don't signal availability. */
7500 *tl++ = txdr_unsigned(layouttype);
7501 *tl++ = txdr_unsigned(iomode);
7502 txdr_hyper(offset, tl);
7503 tl += 2;
7504 txdr_hyper(len, tl);
7505 tl += 2;
7506 txdr_hyper(minlen, tl);
7507 tl += 2;
7508 if (usecurstateid != 0) {
7509 /* Special stateid for Current stateid. */
7510 *tl++ = txdr_unsigned(1);
7511 *tl++ = 0;
7512 *tl++ = 0;
7513 *tl++ = 0;
7514 } else {
7515 *tl++ = txdr_unsigned(stateidp->seqid);
7516 NFSCL_DEBUG(4, "layget seq=%d\n", (int)stateidp->seqid);
7517 *tl++ = stateidp->other[0];
7518 *tl++ = stateidp->other[1];
7519 *tl++ = stateidp->other[2];
7520 }
7521 *tl = txdr_unsigned(layoutlen);
7522 }
7523
7524 /*
7525 * Parse the reply for a successful LayoutGet operation.
7526 */
7527 static int
7528 nfsrv_parselayoutget(struct nfsmount *nmp, struct nfsrv_descript *nd,
7529 nfsv4stateid_t *stateidp, int *retonclosep, struct nfsclflayouthead *flhp)
7530 {
7531 uint32_t *tl;
7532 struct nfsclflayout *flp, *prevflp, *tflp;
7533 int cnt, error, fhcnt, gotiomode, i, iomode, j, k, l, laytype, nfhlen;
7534 int m, mirrorcnt;
7535 uint64_t retlen, off;
7536 struct nfsfh *nfhp;
7537 uint8_t *cp;
7538 uid_t user;
7539 gid_t grp;
7540
7541 NFSCL_DEBUG(4, "in nfsrv_parselayoutget\n");
7542 error = 0;
7543 flp = NULL;
7544 gotiomode = -1;
7545 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_STATEID);
7546 if (*tl++ != 0)
7547 *retonclosep = 1;
7548 else
7549 *retonclosep = 0;
7550 stateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
7551 NFSCL_DEBUG(4, "retoncls=%d stseq=%d\n", *retonclosep,
7552 (int)stateidp->seqid);
7553 stateidp->other[0] = *tl++;
7554 stateidp->other[1] = *tl++;
7555 stateidp->other[2] = *tl++;
7556 cnt = fxdr_unsigned(int, *tl);
7557 NFSCL_DEBUG(4, "layg cnt=%d\n", cnt);
7558 if (cnt <= 0 || cnt > 10000) {
7559 /* Don't accept more than 10000 layouts in reply. */
7560 error = NFSERR_BADXDR;
7561 goto nfsmout;
7562 }
7563 for (i = 0; i < cnt; i++) {
7564 /* Dissect to the layout type. */
7565 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER +
7566 3 * NFSX_UNSIGNED);
7567 off = fxdr_hyper(tl); tl += 2;
7568 retlen = fxdr_hyper(tl); tl += 2;
7569 iomode = fxdr_unsigned(int, *tl++);
7570 laytype = fxdr_unsigned(int, *tl);
7571 NFSCL_DEBUG(4, "layt=%d off=%ju len=%ju iom=%d\n", laytype,
7572 (uintmax_t)off, (uintmax_t)retlen, iomode);
7573 /* Ignore length of layout body for now. */
7574 if (laytype == NFSLAYOUT_NFSV4_1_FILES) {
7575 /* Parse the File layout up to fhcnt. */
7576 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED +
7577 NFSX_HYPER + NFSX_V4DEVICEID);
7578 fhcnt = fxdr_unsigned(int, *(tl + 4 +
7579 NFSX_V4DEVICEID / NFSX_UNSIGNED));
7580 NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt);
7581 if (fhcnt < 0 || fhcnt > 100) {
7582 /* Don't accept more than 100 file handles. */
7583 error = NFSERR_BADXDR;
7584 goto nfsmout;
7585 }
7586 if (fhcnt > 0)
7587 flp = malloc(sizeof(*flp) + fhcnt *
7588 sizeof(struct nfsfh *), M_NFSFLAYOUT,
7589 M_WAITOK);
7590 else
7591 flp = malloc(sizeof(*flp), M_NFSFLAYOUT,
7592 M_WAITOK);
7593 flp->nfsfl_flags = NFSFL_FILE;
7594 flp->nfsfl_fhcnt = 0;
7595 flp->nfsfl_devp = NULL;
7596 flp->nfsfl_off = off;
7597 if (flp->nfsfl_off + retlen < flp->nfsfl_off)
7598 flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off;
7599 else
7600 flp->nfsfl_end = flp->nfsfl_off + retlen;
7601 flp->nfsfl_iomode = iomode;
7602 if (gotiomode == -1)
7603 gotiomode = flp->nfsfl_iomode;
7604 /* Ignore layout body length for now. */
7605 NFSBCOPY(tl, flp->nfsfl_dev, NFSX_V4DEVICEID);
7606 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
7607 flp->nfsfl_util = fxdr_unsigned(uint32_t, *tl++);
7608 NFSCL_DEBUG(4, "flutil=0x%x\n", flp->nfsfl_util);
7609 mtx_lock(&nmp->nm_mtx);
7610 if (nmp->nm_minorvers > 1 && (flp->nfsfl_util &
7611 NFSFLAYUTIL_IOADVISE_THRU_MDS) != 0)
7612 nmp->nm_privflag |= NFSMNTP_IOADVISETHRUMDS;
7613 mtx_unlock(&nmp->nm_mtx);
7614 flp->nfsfl_stripe1 = fxdr_unsigned(uint32_t, *tl++);
7615 flp->nfsfl_patoff = fxdr_hyper(tl); tl += 2;
7616 NFSCL_DEBUG(4, "stripe1=%u poff=%ju\n",
7617 flp->nfsfl_stripe1, (uintmax_t)flp->nfsfl_patoff);
7618 for (j = 0; j < fhcnt; j++) {
7619 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
7620 nfhlen = fxdr_unsigned(int, *tl);
7621 if (nfhlen <= 0 || nfhlen > NFSX_V4FHMAX) {
7622 error = NFSERR_BADXDR;
7623 goto nfsmout;
7624 }
7625 nfhp = malloc(sizeof(*nfhp) + nfhlen - 1,
7626 M_NFSFH, M_WAITOK);
7627 flp->nfsfl_fh[j] = nfhp;
7628 flp->nfsfl_fhcnt++;
7629 nfhp->nfh_len = nfhlen;
7630 NFSM_DISSECT(cp, uint8_t *, NFSM_RNDUP(nfhlen));
7631 NFSBCOPY(cp, nfhp->nfh_fh, nfhlen);
7632 }
7633 } else if (laytype == NFSLAYOUT_FLEXFILE) {
7634 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED +
7635 NFSX_HYPER);
7636 mirrorcnt = fxdr_unsigned(int, *(tl + 2));
7637 NFSCL_DEBUG(4, "mirrorcnt=%d\n", mirrorcnt);
7638 if (mirrorcnt < 1 || mirrorcnt > NFSDEV_MAXMIRRORS) {
7639 error = NFSERR_BADXDR;
7640 goto nfsmout;
7641 }
7642 flp = malloc(sizeof(*flp) + mirrorcnt *
7643 sizeof(struct nfsffm), M_NFSFLAYOUT, M_WAITOK);
7644 flp->nfsfl_flags = NFSFL_FLEXFILE;
7645 flp->nfsfl_mirrorcnt = mirrorcnt;
7646 for (j = 0; j < mirrorcnt; j++)
7647 flp->nfsfl_ffm[j].devp = NULL;
7648 flp->nfsfl_off = off;
7649 if (flp->nfsfl_off + retlen < flp->nfsfl_off)
7650 flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off;
7651 else
7652 flp->nfsfl_end = flp->nfsfl_off + retlen;
7653 flp->nfsfl_iomode = iomode;
7654 if (gotiomode == -1)
7655 gotiomode = flp->nfsfl_iomode;
7656 flp->nfsfl_stripeunit = fxdr_hyper(tl);
7657 NFSCL_DEBUG(4, "stripeunit=%ju\n",
7658 (uintmax_t)flp->nfsfl_stripeunit);
7659 for (j = 0; j < mirrorcnt; j++) {
7660 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
7661 k = fxdr_unsigned(int, *tl);
7662 if (k < 1 || k > 128) {
7663 error = NFSERR_BADXDR;
7664 goto nfsmout;
7665 }
7666 NFSCL_DEBUG(4, "servercnt=%d\n", k);
7667 for (l = 0; l < k; l++) {
7668 NFSM_DISSECT(tl, uint32_t *,
7669 NFSX_V4DEVICEID + NFSX_STATEID +
7670 2 * NFSX_UNSIGNED);
7671 if (l == 0) {
7672 /* Just use the first server. */
7673 NFSBCOPY(tl,
7674 flp->nfsfl_ffm[j].dev,
7675 NFSX_V4DEVICEID);
7676 tl += (NFSX_V4DEVICEID /
7677 NFSX_UNSIGNED);
7678 tl++;
7679 flp->nfsfl_ffm[j].st.seqid =
7680 *tl++;
7681 flp->nfsfl_ffm[j].st.other[0] =
7682 *tl++;
7683 flp->nfsfl_ffm[j].st.other[1] =
7684 *tl++;
7685 flp->nfsfl_ffm[j].st.other[2] =
7686 *tl++;
7687 NFSCL_DEBUG(4, "st.seqid=%u "
7688 "st.o0=0x%x st.o1=0x%x "
7689 "st.o2=0x%x\n",
7690 flp->nfsfl_ffm[j].st.seqid,
7691 flp->nfsfl_ffm[j].st.other[0],
7692 flp->nfsfl_ffm[j].st.other[1],
7693 flp->nfsfl_ffm[j].st.other[2]);
7694 } else
7695 tl += ((NFSX_V4DEVICEID +
7696 NFSX_STATEID +
7697 NFSX_UNSIGNED) /
7698 NFSX_UNSIGNED);
7699 fhcnt = fxdr_unsigned(int, *tl);
7700 NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt);
7701 if (fhcnt < 1 ||
7702 fhcnt > NFSDEV_MAXVERS) {
7703 error = NFSERR_BADXDR;
7704 goto nfsmout;
7705 }
7706 for (m = 0; m < fhcnt; m++) {
7707 NFSM_DISSECT(tl, uint32_t *,
7708 NFSX_UNSIGNED);
7709 nfhlen = fxdr_unsigned(int,
7710 *tl);
7711 NFSCL_DEBUG(4, "nfhlen=%d\n",
7712 nfhlen);
7713 if (nfhlen <= 0 || nfhlen >
7714 NFSX_V4FHMAX) {
7715 error = NFSERR_BADXDR;
7716 goto nfsmout;
7717 }
7718 NFSM_DISSECT(cp, uint8_t *,
7719 NFSM_RNDUP(nfhlen));
7720 if (l == 0) {
7721 flp->nfsfl_ffm[j].fhcnt
7722 = fhcnt;
7723 nfhp = malloc(
7724 sizeof(*nfhp) +
7725 nfhlen - 1, M_NFSFH,
7726 M_WAITOK);
7727 flp->nfsfl_ffm[j].fh[m]
7728 = nfhp;
7729 nfhp->nfh_len = nfhlen;
7730 NFSBCOPY(cp,
7731 nfhp->nfh_fh,
7732 nfhlen);
7733 NFSCL_DEBUG(4,
7734 "got fh\n");
7735 }
7736 }
7737 /* Now, get the ffsd_user/ffds_group. */
7738 error = nfsrv_parseug(nd, 0, &user,
7739 &grp, curthread);
7740 NFSCL_DEBUG(4, "after parseu=%d\n",
7741 error);
7742 if (error == 0)
7743 error = nfsrv_parseug(nd, 1,
7744 &user, &grp, curthread);
7745 NFSCL_DEBUG(4, "aft parseg=%d\n",
7746 grp);
7747 if (error != 0)
7748 goto nfsmout;
7749 NFSCL_DEBUG(4, "user=%d group=%d\n",
7750 user, grp);
7751 if (l == 0) {
7752 flp->nfsfl_ffm[j].user = user;
7753 flp->nfsfl_ffm[j].group = grp;
7754 NFSCL_DEBUG(4,
7755 "usr=%d grp=%d\n", user,
7756 grp);
7757 }
7758 }
7759 }
7760 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
7761 flp->nfsfl_fflags = fxdr_unsigned(uint32_t, *tl++);
7762 #ifdef notnow
7763 /*
7764 * At this time, there is no flag.
7765 * NFSFLEXFLAG_IOADVISE_THRU_MDS might need to be
7766 * added, or it may never exist?
7767 */
7768 mtx_lock(&nmp->nm_mtx);
7769 if (nmp->nm_minorvers > 1 && (flp->nfsfl_fflags &
7770 NFSFLEXFLAG_IOADVISE_THRU_MDS) != 0)
7771 nmp->nm_privflag |= NFSMNTP_IOADVISETHRUMDS;
7772 mtx_unlock(&nmp->nm_mtx);
7773 #endif
7774 flp->nfsfl_statshint = fxdr_unsigned(uint32_t, *tl);
7775 NFSCL_DEBUG(4, "fflags=0x%x statshint=%d\n",
7776 flp->nfsfl_fflags, flp->nfsfl_statshint);
7777 } else {
7778 error = NFSERR_BADXDR;
7779 goto nfsmout;
7780 }
7781 if (flp->nfsfl_iomode == gotiomode) {
7782 /* Keep the list in increasing offset order. */
7783 tflp = LIST_FIRST(flhp);
7784 prevflp = NULL;
7785 while (tflp != NULL &&
7786 tflp->nfsfl_off < flp->nfsfl_off) {
7787 prevflp = tflp;
7788 tflp = LIST_NEXT(tflp, nfsfl_list);
7789 }
7790 if (prevflp == NULL)
7791 LIST_INSERT_HEAD(flhp, flp, nfsfl_list);
7792 else
7793 LIST_INSERT_AFTER(prevflp, flp,
7794 nfsfl_list);
7795 NFSCL_DEBUG(4, "flp inserted\n");
7796 } else {
7797 printf("nfscl_layoutget(): got wrong iomode\n");
7798 nfscl_freeflayout(flp);
7799 }
7800 flp = NULL;
7801 }
7802 nfsmout:
7803 NFSCL_DEBUG(4, "eo nfsrv_parselayoutget=%d\n", error);
7804 if (error != 0 && flp != NULL)
7805 nfscl_freeflayout(flp);
7806 return (error);
7807 }
7808
7809 /*
7810 * Parse a user/group digit string.
7811 */
7812 static int
7813 nfsrv_parseug(struct nfsrv_descript *nd, int dogrp, uid_t *uidp, gid_t *gidp,
7814 NFSPROC_T *p)
7815 {
7816 uint32_t *tl;
7817 char *cp, *str, str0[NFSV4_SMALLSTR + 1];
7818 uint32_t len = 0;
7819 int error = 0;
7820
7821 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
7822 len = fxdr_unsigned(uint32_t, *tl);
7823 str = NULL;
7824 if (len > NFSV4_OPAQUELIMIT) {
7825 error = NFSERR_BADXDR;
7826 goto nfsmout;
7827 }
7828 NFSCL_DEBUG(4, "nfsrv_parseug: len=%d\n", len);
7829 if (len == 0) {
7830 if (dogrp != 0)
7831 *gidp = GID_NOGROUP;
7832 else
7833 *uidp = UID_NOBODY;
7834 return (0);
7835 }
7836 if (len > NFSV4_SMALLSTR)
7837 str = malloc(len + 1, M_TEMP, M_WAITOK);
7838 else
7839 str = str0;
7840 NFSM_DISSECT(cp, char *, NFSM_RNDUP(len));
7841 NFSBCOPY(cp, str, len);
7842 str[len] = '\0';
7843 NFSCL_DEBUG(4, "nfsrv_parseug: str=%s\n", str);
7844 if (dogrp != 0)
7845 error = nfsv4_strtogid(nd, str, len, gidp);
7846 else
7847 error = nfsv4_strtouid(nd, str, len, uidp);
7848 nfsmout:
7849 if (len > NFSV4_SMALLSTR)
7850 free(str, M_TEMP);
7851 NFSCL_DEBUG(4, "eo nfsrv_parseug=%d\n", error);
7852 return (error);
7853 }
7854
7855 /*
7856 * Similar to nfsrpc_getlayout(), except that it uses nfsrpc_openlayget(),
7857 * so that it does both an Open and a Layoutget.
7858 */
7859 static int
7860 nfsrpc_getopenlayout(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp,
7861 int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode,
7862 struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp,
7863 struct ucred *cred, NFSPROC_T *p)
7864 {
7865 struct nfscllayout *lyp;
7866 struct nfsclflayout *flp;
7867 struct nfsclflayouthead flh;
7868 int error, islocked, layoutlen, recalled, retonclose, usecurstateid;
7869 int layouttype, laystat;
7870 nfsv4stateid_t stateid;
7871 struct nfsclsession *tsep;
7872
7873 error = 0;
7874 if (NFSHASFLEXFILE(nmp))
7875 layouttype = NFSLAYOUT_FLEXFILE;
7876 else
7877 layouttype = NFSLAYOUT_NFSV4_1_FILES;
7878 /*
7879 * If lyp is returned non-NULL, there will be a refcnt (shared lock)
7880 * on it, iff flp != NULL or a lock (exclusive lock) on it iff
7881 * flp == NULL.
7882 */
7883 lyp = nfscl_getlayout(nmp->nm_clp, newfhp, newfhlen, 0, mode, &flp,
7884 &recalled);
7885 NFSCL_DEBUG(4, "nfsrpc_getopenlayout nfscl_getlayout lyp=%p\n", lyp);
7886 if (lyp == NULL)
7887 islocked = 0;
7888 else if (flp != NULL)
7889 islocked = 1;
7890 else
7891 islocked = 2;
7892 if ((lyp == NULL || flp == NULL) && recalled == 0) {
7893 LIST_INIT(&flh);
7894 tsep = nfsmnt_mdssession(nmp);
7895 layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID +
7896 3 * NFSX_UNSIGNED);
7897 if (lyp == NULL)
7898 usecurstateid = 1;
7899 else {
7900 usecurstateid = 0;
7901 stateid.seqid = lyp->nfsly_stateid.seqid;
7902 stateid.other[0] = lyp->nfsly_stateid.other[0];
7903 stateid.other[1] = lyp->nfsly_stateid.other[1];
7904 stateid.other[2] = lyp->nfsly_stateid.other[2];
7905 }
7906 error = nfsrpc_openlayoutrpc(nmp, vp, nfhp, fhlen,
7907 newfhp, newfhlen, mode, op, name, namelen,
7908 dpp, &stateid, usecurstateid, layouttype, layoutlen,
7909 &retonclose, &flh, &laystat, cred, p);
7910 NFSCL_DEBUG(4, "aft nfsrpc_openlayoutrpc laystat=%d err=%d\n",
7911 laystat, error);
7912 laystat = nfsrpc_layoutgetres(nmp, vp, newfhp, newfhlen,
7913 &stateid, retonclose, NULL, &lyp, &flh, layouttype, laystat,
7914 &islocked, cred, p);
7915 } else
7916 error = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp, newfhlen,
7917 mode, op, name, namelen, dpp, 0, 0, cred, p, 0, 0);
7918 if (islocked == 2)
7919 nfscl_rellayout(lyp, 1);
7920 else if (islocked == 1)
7921 nfscl_rellayout(lyp, 0);
7922 return (error);
7923 }
7924
7925 /*
7926 * This function does an Open+LayoutGet for an NFSv4.1 mount with pNFS
7927 * enabled, only for the CLAIM_NULL case. All other NFSv4 Opens are
7928 * handled by nfsrpc_openrpc().
7929 * For the case where op == NULL, dvp is the directory. When op != NULL, it
7930 * can be NULL.
7931 */
7932 static int
7933 nfsrpc_openlayoutrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp,
7934 int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode,
7935 struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp,
7936 nfsv4stateid_t *stateidp, int usecurstateid, int layouttype,
7937 int layoutlen, int *retonclosep, struct nfsclflayouthead *flhp,
7938 int *laystatp, struct ucred *cred, NFSPROC_T *p)
7939 {
7940 uint32_t *tl;
7941 struct nfsrv_descript nfsd, *nd = &nfsd;
7942 struct nfscldeleg *ndp = NULL;
7943 struct nfsvattr nfsva;
7944 struct nfsclsession *tsep;
7945 uint32_t rflags, deleg;
7946 nfsattrbit_t attrbits;
7947 int error, ret, acesize, limitby, iomode;
7948
7949 *dpp = NULL;
7950 *laystatp = ENXIO;
7951 nfscl_reqstart(nd, NFSPROC_OPENLAYGET, nmp, nfhp, fhlen, NULL, NULL,
7952 0, 0, cred);
7953 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
7954 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
7955 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
7956 *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
7957 tsep = nfsmnt_mdssession(nmp);
7958 *tl++ = tsep->nfsess_clientid.lval[0];
7959 *tl = tsep->nfsess_clientid.lval[1];
7960 nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN);
7961 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
7962 *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE);
7963 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
7964 nfsm_strtom(nd, name, namelen);
7965 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
7966 *tl = txdr_unsigned(NFSV4OP_GETATTR);
7967 NFSZERO_ATTRBIT(&attrbits);
7968 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
7969 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY);
7970 nfsrv_putattrbit(nd, &attrbits);
7971 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
7972 *tl = txdr_unsigned(NFSV4OP_LAYOUTGET);
7973 if ((mode & NFSV4OPEN_ACCESSWRITE) != 0)
7974 iomode = NFSLAYOUTIOMODE_RW;
7975 else
7976 iomode = NFSLAYOUTIOMODE_READ;
7977 nfsrv_setuplayoutget(nd, iomode, 0, UINT64_MAX, 0, stateidp,
7978 layouttype, layoutlen, usecurstateid);
7979 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
7980 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
7981 if (error != 0)
7982 return (error);
7983 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
7984 if (nd->nd_repstat != 0)
7985 *laystatp = nd->nd_repstat;
7986 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
7987 /* ND_NOMOREDATA will be set if the Open operation failed. */
7988 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
7989 6 * NFSX_UNSIGNED);
7990 op->nfso_stateid.seqid = *tl++;
7991 op->nfso_stateid.other[0] = *tl++;
7992 op->nfso_stateid.other[1] = *tl++;
7993 op->nfso_stateid.other[2] = *tl;
7994 rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
7995 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
7996 if (error != 0)
7997 goto nfsmout;
7998 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
7999 deleg = fxdr_unsigned(u_int32_t, *tl);
8000 if (deleg == NFSV4OPEN_DELEGATEREAD ||
8001 deleg == NFSV4OPEN_DELEGATEWRITE) {
8002 if (!(op->nfso_own->nfsow_clp->nfsc_flags &
8003 NFSCLFLAGS_FIRSTDELEG))
8004 op->nfso_own->nfsow_clp->nfsc_flags |=
8005 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
8006 ndp = malloc(sizeof(struct nfscldeleg) + newfhlen,
8007 M_NFSCLDELEG, M_WAITOK);
8008 LIST_INIT(&ndp->nfsdl_owner);
8009 LIST_INIT(&ndp->nfsdl_lock);
8010 ndp->nfsdl_clp = op->nfso_own->nfsow_clp;
8011 ndp->nfsdl_fhlen = newfhlen;
8012 NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen);
8013 newnfs_copyincred(cred, &ndp->nfsdl_cred);
8014 nfscl_lockinit(&ndp->nfsdl_rwlock);
8015 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
8016 NFSX_UNSIGNED);
8017 ndp->nfsdl_stateid.seqid = *tl++;
8018 ndp->nfsdl_stateid.other[0] = *tl++;
8019 ndp->nfsdl_stateid.other[1] = *tl++;
8020 ndp->nfsdl_stateid.other[2] = *tl++;
8021 ret = fxdr_unsigned(int, *tl);
8022 if (deleg == NFSV4OPEN_DELEGATEWRITE) {
8023 ndp->nfsdl_flags = NFSCLDL_WRITE;
8024 /*
8025 * Indicates how much the file can grow.
8026 */
8027 NFSM_DISSECT(tl, u_int32_t *,
8028 3 * NFSX_UNSIGNED);
8029 limitby = fxdr_unsigned(int, *tl++);
8030 switch (limitby) {
8031 case NFSV4OPEN_LIMITSIZE:
8032 ndp->nfsdl_sizelimit = fxdr_hyper(tl);
8033 break;
8034 case NFSV4OPEN_LIMITBLOCKS:
8035 ndp->nfsdl_sizelimit =
8036 fxdr_unsigned(u_int64_t, *tl++);
8037 ndp->nfsdl_sizelimit *=
8038 fxdr_unsigned(u_int64_t, *tl);
8039 break;
8040 default:
8041 error = NFSERR_BADXDR;
8042 goto nfsmout;
8043 };
8044 } else
8045 ndp->nfsdl_flags = NFSCLDL_READ;
8046 if (ret != 0)
8047 ndp->nfsdl_flags |= NFSCLDL_RECALL;
8048 error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, false,
8049 &ret, &acesize, p);
8050 if (error != 0)
8051 goto nfsmout;
8052 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
8053 error = NFSERR_BADXDR;
8054 goto nfsmout;
8055 }
8056 if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) != 0 ||
8057 nfscl_assumeposixlocks)
8058 op->nfso_posixlock = 1;
8059 else
8060 op->nfso_posixlock = 0;
8061 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
8062 /* If the 2nd element == NFS_OK, the Getattr succeeded. */
8063 if (*++tl == 0) {
8064 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
8065 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
8066 NULL, NULL, NULL, p, cred);
8067 if (error != 0)
8068 goto nfsmout;
8069 if (ndp != NULL) {
8070 ndp->nfsdl_change = nfsva.na_filerev;
8071 ndp->nfsdl_modtime = nfsva.na_mtime;
8072 ndp->nfsdl_flags |= NFSCLDL_MODTIMESET;
8073 *dpp = ndp;
8074 ndp = NULL;
8075 }
8076 /*
8077 * At this point, the Open has succeeded, so set
8078 * nd_repstat = NFS_OK. If the Layoutget failed,
8079 * this function just won't return a layout.
8080 */
8081 if (nd->nd_repstat == 0) {
8082 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
8083 *laystatp = fxdr_unsigned(int, *++tl);
8084 if (*laystatp == 0) {
8085 error = nfsrv_parselayoutget(nmp, nd,
8086 stateidp, retonclosep, flhp);
8087 if (error != 0)
8088 *laystatp = error;
8089 }
8090 } else
8091 nd->nd_repstat = 0; /* Return 0 for Open. */
8092 }
8093 }
8094 if (nd->nd_repstat != 0 && error == 0)
8095 error = nd->nd_repstat;
8096 nfsmout:
8097 free(ndp, M_NFSCLDELEG);
8098 m_freem(nd->nd_mrep);
8099 return (error);
8100 }
8101
8102 /*
8103 * Similar nfsrpc_createv4(), but also does the LayoutGet operation.
8104 * Used only for mounts with pNFS enabled.
8105 */
8106 static int
8107 nfsrpc_createlayout(vnode_t dvp, char *name, int namelen, struct vattr *vap,
8108 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp,
8109 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
8110 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
8111 int *dattrflagp, int *unlockedp, nfsv4stateid_t *stateidp,
8112 int usecurstateid, int layouttype, int layoutlen, int *retonclosep,
8113 struct nfsclflayouthead *flhp, int *laystatp)
8114 {
8115 uint32_t *tl;
8116 int error = 0, deleg, newone, ret, acesize, limitby;
8117 struct nfsrv_descript nfsd, *nd = &nfsd;
8118 struct nfsclopen *op;
8119 struct nfscldeleg *dp = NULL;
8120 struct nfsnode *np;
8121 struct nfsfh *nfhp;
8122 struct nfsclsession *tsep;
8123 nfsattrbit_t attrbits;
8124 nfsv4stateid_t stateid;
8125 struct nfsmount *nmp;
8126
8127 nmp = VFSTONFS(dvp->v_mount);
8128 np = VTONFS(dvp);
8129 *laystatp = ENXIO;
8130 *unlockedp = 0;
8131 *nfhpp = NULL;
8132 *dpp = NULL;
8133 *attrflagp = 0;
8134 *dattrflagp = 0;
8135 if (namelen > NFS_MAXNAMLEN)
8136 return (ENAMETOOLONG);
8137 NFSCL_REQSTART(nd, NFSPROC_CREATELAYGET, dvp, cred);
8138 /*
8139 * For V4, this is actually an Open op.
8140 */
8141 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
8142 *tl++ = txdr_unsigned(owp->nfsow_seqid);
8143 *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
8144 NFSV4OPEN_ACCESSREAD);
8145 *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE);
8146 tsep = nfsmnt_mdssession(nmp);
8147 *tl++ = tsep->nfsess_clientid.lval[0];
8148 *tl = tsep->nfsess_clientid.lval[1];
8149 nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN);
8150 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
8151 *tl++ = txdr_unsigned(NFSV4OPEN_CREATE);
8152 if ((fmode & O_EXCL) != 0) {
8153 if (NFSHASSESSPERSIST(nmp)) {
8154 /* Use GUARDED for persistent sessions. */
8155 *tl = txdr_unsigned(NFSCREATE_GUARDED);
8156 nfscl_fillsattr(nd, vap, dvp, 0, 0);
8157 } else {
8158 /* Otherwise, use EXCLUSIVE4_1. */
8159 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41);
8160 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
8161 *tl++ = cverf.lval[0];
8162 *tl = cverf.lval[1];
8163 nfscl_fillsattr(nd, vap, dvp, 0, 0);
8164 }
8165 } else {
8166 *tl = txdr_unsigned(NFSCREATE_UNCHECKED);
8167 nfscl_fillsattr(nd, vap, dvp, 0, 0);
8168 }
8169 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
8170 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
8171 nfsm_strtom(nd, name, namelen);
8172 /* Get the new file's handle and attributes, plus save the FH. */
8173 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
8174 *tl++ = txdr_unsigned(NFSV4OP_SAVEFH);
8175 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
8176 *tl = txdr_unsigned(NFSV4OP_GETATTR);
8177 NFSGETATTR_ATTRBIT(&attrbits);
8178 nfsrv_putattrbit(nd, &attrbits);
8179 /* Get the directory's post-op attributes. */
8180 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
8181 *tl = txdr_unsigned(NFSV4OP_PUTFH);
8182 nfsm_fhtom(nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0);
8183 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
8184 *tl = txdr_unsigned(NFSV4OP_GETATTR);
8185 nfsrv_putattrbit(nd, &attrbits);
8186 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
8187 *tl++ = txdr_unsigned(NFSV4OP_RESTOREFH);
8188 *tl = txdr_unsigned(NFSV4OP_LAYOUTGET);
8189 nfsrv_setuplayoutget(nd, NFSLAYOUTIOMODE_RW, 0, UINT64_MAX, 0, stateidp,
8190 layouttype, layoutlen, usecurstateid);
8191 error = nfscl_request(nd, dvp, p, cred);
8192 if (error != 0)
8193 return (error);
8194 NFSCL_DEBUG(4, "nfsrpc_createlayout stat=%d err=%d\n", nd->nd_repstat,
8195 error);
8196 if (nd->nd_repstat != 0)
8197 *laystatp = nd->nd_repstat;
8198 NFSCL_INCRSEQID(owp->nfsow_seqid, nd);
8199 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
8200 NFSCL_DEBUG(4, "nfsrpc_createlayout open succeeded\n");
8201 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
8202 6 * NFSX_UNSIGNED);
8203 stateid.seqid = *tl++;
8204 stateid.other[0] = *tl++;
8205 stateid.other[1] = *tl++;
8206 stateid.other[2] = *tl;
8207 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
8208 if (error != 0)
8209 goto nfsmout;
8210 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
8211 deleg = fxdr_unsigned(int, *tl);
8212 if (deleg == NFSV4OPEN_DELEGATEREAD ||
8213 deleg == NFSV4OPEN_DELEGATEWRITE) {
8214 if (!(owp->nfsow_clp->nfsc_flags &
8215 NFSCLFLAGS_FIRSTDELEG))
8216 owp->nfsow_clp->nfsc_flags |=
8217 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
8218 dp = malloc(sizeof(struct nfscldeleg) + NFSX_V4FHMAX,
8219 M_NFSCLDELEG, M_WAITOK);
8220 LIST_INIT(&dp->nfsdl_owner);
8221 LIST_INIT(&dp->nfsdl_lock);
8222 dp->nfsdl_clp = owp->nfsow_clp;
8223 newnfs_copyincred(cred, &dp->nfsdl_cred);
8224 nfscl_lockinit(&dp->nfsdl_rwlock);
8225 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
8226 NFSX_UNSIGNED);
8227 dp->nfsdl_stateid.seqid = *tl++;
8228 dp->nfsdl_stateid.other[0] = *tl++;
8229 dp->nfsdl_stateid.other[1] = *tl++;
8230 dp->nfsdl_stateid.other[2] = *tl++;
8231 ret = fxdr_unsigned(int, *tl);
8232 if (deleg == NFSV4OPEN_DELEGATEWRITE) {
8233 dp->nfsdl_flags = NFSCLDL_WRITE;
8234 /*
8235 * Indicates how much the file can grow.
8236 */
8237 NFSM_DISSECT(tl, u_int32_t *,
8238 3 * NFSX_UNSIGNED);
8239 limitby = fxdr_unsigned(int, *tl++);
8240 switch (limitby) {
8241 case NFSV4OPEN_LIMITSIZE:
8242 dp->nfsdl_sizelimit = fxdr_hyper(tl);
8243 break;
8244 case NFSV4OPEN_LIMITBLOCKS:
8245 dp->nfsdl_sizelimit =
8246 fxdr_unsigned(u_int64_t, *tl++);
8247 dp->nfsdl_sizelimit *=
8248 fxdr_unsigned(u_int64_t, *tl);
8249 break;
8250 default:
8251 error = NFSERR_BADXDR;
8252 goto nfsmout;
8253 };
8254 } else {
8255 dp->nfsdl_flags = NFSCLDL_READ;
8256 }
8257 if (ret != 0)
8258 dp->nfsdl_flags |= NFSCLDL_RECALL;
8259 error = nfsrv_dissectace(nd, &dp->nfsdl_ace, false,
8260 &ret, &acesize, p);
8261 if (error != 0)
8262 goto nfsmout;
8263 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
8264 error = NFSERR_BADXDR;
8265 goto nfsmout;
8266 }
8267
8268 /* Now, we should have the status for the SaveFH. */
8269 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
8270 if (*++tl == 0) {
8271 NFSCL_DEBUG(4, "nfsrpc_createlayout SaveFH ok\n");
8272 /*
8273 * Now, process the GetFH and Getattr for the newly
8274 * created file. nfscl_mtofh() will set
8275 * ND_NOMOREDATA if these weren't successful.
8276 */
8277 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
8278 NFSCL_DEBUG(4, "aft nfscl_mtofh err=%d\n", error);
8279 if (error != 0)
8280 goto nfsmout;
8281 } else
8282 nd->nd_flag |= ND_NOMOREDATA;
8283 /* Now we have the PutFH and Getattr for the directory. */
8284 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
8285 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
8286 if (*++tl != 0)
8287 nd->nd_flag |= ND_NOMOREDATA;
8288 else {
8289 NFSM_DISSECT(tl, uint32_t *, 2 *
8290 NFSX_UNSIGNED);
8291 if (*++tl != 0)
8292 nd->nd_flag |= ND_NOMOREDATA;
8293 }
8294 }
8295 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
8296 /* Load the directory attributes. */
8297 error = nfsm_loadattr(nd, dnap);
8298 NFSCL_DEBUG(4, "aft nfsm_loadattr err=%d\n", error);
8299 if (error != 0)
8300 goto nfsmout;
8301 *dattrflagp = 1;
8302 if (dp != NULL && *attrflagp != 0) {
8303 dp->nfsdl_change = nnap->na_filerev;
8304 dp->nfsdl_modtime = nnap->na_mtime;
8305 dp->nfsdl_flags |= NFSCLDL_MODTIMESET;
8306 }
8307 /*
8308 * We can now complete the Open state.
8309 */
8310 nfhp = *nfhpp;
8311 if (dp != NULL) {
8312 dp->nfsdl_fhlen = nfhp->nfh_len;
8313 NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh,
8314 nfhp->nfh_len);
8315 }
8316 /*
8317 * Get an Open structure that will be
8318 * attached to the OpenOwner, acquired already.
8319 */
8320 error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len,
8321 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0,
8322 cred, p, NULL, &op, &newone, NULL, 0, false);
8323 if (error != 0)
8324 goto nfsmout;
8325 op->nfso_stateid = stateid;
8326 newnfs_copyincred(cred, &op->nfso_cred);
8327
8328 nfscl_openrelease(nmp, op, error, newone);
8329 *unlockedp = 1;
8330
8331 /* Now, handle the RestoreFH and LayoutGet. */
8332 if (nd->nd_repstat == 0) {
8333 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
8334 *laystatp = fxdr_unsigned(int, *(tl + 3));
8335 if (*laystatp == 0) {
8336 error = nfsrv_parselayoutget(nmp, nd,
8337 stateidp, retonclosep, flhp);
8338 if (error != 0)
8339 *laystatp = error;
8340 }
8341 NFSCL_DEBUG(4, "aft nfsrv_parselayout err=%d\n",
8342 error);
8343 } else
8344 nd->nd_repstat = 0;
8345 }
8346 }
8347 if (nd->nd_repstat != 0 && error == 0)
8348 error = nd->nd_repstat;
8349 if (error == NFSERR_STALECLIENTID)
8350 nfscl_initiate_recovery(owp->nfsow_clp);
8351 nfsmout:
8352 NFSCL_DEBUG(4, "eo nfsrpc_createlayout err=%d\n", error);
8353 if (error == 0)
8354 *dpp = dp;
8355 else
8356 free(dp, M_NFSCLDELEG);
8357 m_freem(nd->nd_mrep);
8358 return (error);
8359 }
8360
8361 /*
8362 * Similar to nfsrpc_getopenlayout(), except that it used for the Create case.
8363 */
8364 static int
8365 nfsrpc_getcreatelayout(vnode_t dvp, char *name, int namelen, struct vattr *vap,
8366 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp,
8367 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
8368 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
8369 int *dattrflagp, int *unlockedp)
8370 {
8371 struct nfscllayout *lyp;
8372 struct nfsclflayouthead flh;
8373 struct nfsfh *nfhp;
8374 struct nfsclsession *tsep;
8375 struct nfsmount *nmp;
8376 nfsv4stateid_t stateid;
8377 int error, layoutlen, layouttype, retonclose, laystat;
8378
8379 error = 0;
8380 nmp = VFSTONFS(dvp->v_mount);
8381 if (NFSHASFLEXFILE(nmp))
8382 layouttype = NFSLAYOUT_FLEXFILE;
8383 else
8384 layouttype = NFSLAYOUT_NFSV4_1_FILES;
8385 LIST_INIT(&flh);
8386 tsep = nfsmnt_mdssession(nmp);
8387 layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID + 3 * NFSX_UNSIGNED);
8388 error = nfsrpc_createlayout(dvp, name, namelen, vap, cverf, fmode,
8389 owp, dpp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp,
8390 unlockedp, &stateid, 1, layouttype, layoutlen, &retonclose,
8391 &flh, &laystat);
8392 NFSCL_DEBUG(4, "aft nfsrpc_createlayoutrpc laystat=%d err=%d\n",
8393 laystat, error);
8394 lyp = NULL;
8395 if (laystat == 0) {
8396 nfhp = *nfhpp;
8397 laystat = nfsrpc_layoutgetres(nmp, dvp, nfhp->nfh_fh,
8398 nfhp->nfh_len, &stateid, retonclose, NULL, &lyp, &flh,
8399 layouttype, laystat, NULL, cred, p);
8400 } else
8401 laystat = nfsrpc_layoutgetres(nmp, dvp, NULL, 0, &stateid,
8402 retonclose, NULL, &lyp, &flh, layouttype, laystat, NULL,
8403 cred, p);
8404 if (laystat == 0)
8405 nfscl_rellayout(lyp, 0);
8406 return (error);
8407 }
8408
8409 /*
8410 * Process the results of a layoutget() operation.
8411 */
8412 static int
8413 nfsrpc_layoutgetres(struct nfsmount *nmp, vnode_t vp, uint8_t *newfhp,
8414 int newfhlen, nfsv4stateid_t *stateidp, int retonclose, uint32_t *notifybit,
8415 struct nfscllayout **lypp, struct nfsclflayouthead *flhp, int layouttype,
8416 int laystat, int *islockedp, struct ucred *cred, NFSPROC_T *p)
8417 {
8418 struct nfsclflayout *tflp;
8419 struct nfscldevinfo *dip;
8420 uint8_t *dev;
8421 int i, mirrorcnt;
8422
8423 if (laystat == NFSERR_UNKNLAYOUTTYPE) {
8424 NFSLOCKMNT(nmp);
8425 if (!NFSHASFLEXFILE(nmp)) {
8426 /* Switch to using Flex File Layout. */
8427 nmp->nm_state |= NFSSTA_FLEXFILE;
8428 } else if (layouttype == NFSLAYOUT_FLEXFILE) {
8429 /* Disable pNFS. */
8430 NFSCL_DEBUG(1, "disable PNFS\n");
8431 nmp->nm_state &= ~(NFSSTA_PNFS | NFSSTA_FLEXFILE);
8432 }
8433 NFSUNLOCKMNT(nmp);
8434 }
8435 if (laystat == 0) {
8436 NFSCL_DEBUG(4, "nfsrpc_layoutgetres at FOREACH\n");
8437 LIST_FOREACH(tflp, flhp, nfsfl_list) {
8438 if (layouttype == NFSLAYOUT_FLEXFILE)
8439 mirrorcnt = tflp->nfsfl_mirrorcnt;
8440 else
8441 mirrorcnt = 1;
8442 for (i = 0; i < mirrorcnt; i++) {
8443 laystat = nfscl_adddevinfo(nmp, NULL, i, tflp);
8444 NFSCL_DEBUG(4, "aft adddev=%d\n", laystat);
8445 if (laystat != 0) {
8446 if (layouttype == NFSLAYOUT_FLEXFILE)
8447 dev = tflp->nfsfl_ffm[i].dev;
8448 else
8449 dev = tflp->nfsfl_dev;
8450 laystat = nfsrpc_getdeviceinfo(nmp, dev,
8451 layouttype, notifybit, &dip, cred,
8452 p);
8453 NFSCL_DEBUG(4, "aft nfsrpc_gdi=%d\n",
8454 laystat);
8455 if (laystat != 0)
8456 goto out;
8457 laystat = nfscl_adddevinfo(nmp, dip, i,
8458 tflp);
8459 if (laystat != 0)
8460 printf("nfsrpc_layoutgetresout"
8461 ": cannot add\n");
8462 }
8463 }
8464 }
8465 }
8466 out:
8467 if (laystat == 0) {
8468 /*
8469 * nfscl_layout() always returns with the nfsly_lock
8470 * set to a refcnt (shared lock).
8471 * Passing in dvp is sufficient, since it is only used to
8472 * get the fsid for the file system.
8473 */
8474 laystat = nfscl_layout(nmp, vp, newfhp, newfhlen, stateidp,
8475 layouttype, retonclose, flhp, lypp, cred, p);
8476 NFSCL_DEBUG(4, "nfsrpc_layoutgetres: aft nfscl_layout=%d\n",
8477 laystat);
8478 if (laystat == 0 && islockedp != NULL)
8479 *islockedp = 1;
8480 }
8481 return (laystat);
8482 }
8483
8484 /*
8485 * nfs copy_file_range operation.
8486 */
8487 int
8488 nfsrpc_copy_file_range(vnode_t invp, off_t *inoffp, vnode_t outvp,
8489 off_t *outoffp, size_t *lenp, unsigned int flags, int *inattrflagp,
8490 struct nfsvattr *innap, int *outattrflagp, struct nfsvattr *outnap,
8491 struct ucred *cred, bool consecutive, bool *must_commitp)
8492 {
8493 int commit, error, expireret = 0, retrycnt;
8494 u_int32_t clidrev = 0;
8495 struct nfsmount *nmp = VFSTONFS(invp->v_mount);
8496 struct nfsfh *innfhp = NULL, *outnfhp = NULL;
8497 nfsv4stateid_t instateid, outstateid;
8498 void *inlckp, *outlckp;
8499
8500 if (nmp->nm_clp != NULL)
8501 clidrev = nmp->nm_clp->nfsc_clientidrev;
8502 innfhp = VTONFS(invp)->n_fhp;
8503 outnfhp = VTONFS(outvp)->n_fhp;
8504 retrycnt = 0;
8505 do {
8506 /* Get both stateids. */
8507 inlckp = NULL;
8508 nfscl_getstateid(invp, innfhp->nfh_fh, innfhp->nfh_len,
8509 NFSV4OPEN_ACCESSREAD, 0, NULL, curthread, &instateid,
8510 &inlckp);
8511 outlckp = NULL;
8512 nfscl_getstateid(outvp, outnfhp->nfh_fh, outnfhp->nfh_len,
8513 NFSV4OPEN_ACCESSWRITE, 0, NULL, curthread, &outstateid,
8514 &outlckp);
8515
8516 error = nfsrpc_copyrpc(invp, *inoffp, outvp, *outoffp, lenp,
8517 &instateid, &outstateid, innap, inattrflagp, outnap,
8518 outattrflagp, consecutive, &commit, cred, curthread);
8519 if (error == 0) {
8520 if (commit != NFSWRITE_FILESYNC)
8521 *must_commitp = true;
8522 *inoffp += *lenp;
8523 *outoffp += *lenp;
8524 } else if (error == NFSERR_STALESTATEID)
8525 nfscl_initiate_recovery(nmp->nm_clp);
8526 if (inlckp != NULL)
8527 nfscl_lockderef(inlckp);
8528 if (outlckp != NULL)
8529 nfscl_lockderef(outlckp);
8530 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
8531 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
8532 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
8533 (void) nfs_catnap(PZERO, error, "nfs_cfr");
8534 } else if ((error == NFSERR_EXPIRED || (!NFSHASINT(nmp) &&
8535 error == NFSERR_BADSTATEID)) && clidrev != 0) {
8536 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev,
8537 curthread);
8538 } else if (error == NFSERR_BADSTATEID && NFSHASINT(nmp)) {
8539 error = EIO;
8540 }
8541 retrycnt++;
8542 } while (error == NFSERR_GRACE || error == NFSERR_DELAY ||
8543 error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION ||
8544 error == NFSERR_STALEDONTRECOVER ||
8545 (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
8546 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
8547 expireret == 0 && clidrev != 0 && retrycnt < 4));
8548 if (error != 0 && (retrycnt >= 4 ||
8549 error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION ||
8550 error == NFSERR_STALEDONTRECOVER))
8551 error = EIO;
8552 return (error);
8553 }
8554
8555 /*
8556 * The copy RPC.
8557 */
8558 static int
8559 nfsrpc_copyrpc(vnode_t invp, off_t inoff, vnode_t outvp, off_t outoff,
8560 size_t *lenp, nfsv4stateid_t *instateidp, nfsv4stateid_t *outstateidp,
8561 struct nfsvattr *innap, int *inattrflagp, struct nfsvattr *outnap,
8562 int *outattrflagp, bool consecutive, int *commitp, struct ucred *cred,
8563 NFSPROC_T *p)
8564 {
8565 uint32_t *tl;
8566 int error;
8567 struct nfsrv_descript nfsd;
8568 struct nfsrv_descript *nd = &nfsd;
8569 struct nfsmount *nmp;
8570 nfsattrbit_t attrbits;
8571 uint64_t len;
8572
8573 nmp = VFSTONFS(outvp->v_mount);
8574 *inattrflagp = *outattrflagp = 0;
8575 *commitp = NFSWRITE_UNSTABLE;
8576 len = *lenp;
8577 *lenp = 0;
8578 if (len > nfs_maxcopyrange)
8579 len = nfs_maxcopyrange;
8580 NFSCL_REQSTART(nd, NFSPROC_COPY, invp, cred);
8581 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
8582 *tl = txdr_unsigned(NFSV4OP_GETATTR);
8583 NFSGETATTR_ATTRBIT(&attrbits);
8584 nfsrv_putattrbit(nd, &attrbits);
8585 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
8586 *tl = txdr_unsigned(NFSV4OP_PUTFH);
8587 nfsm_fhtom(nd, VTONFS(outvp)->n_fhp->nfh_fh,
8588 VTONFS(outvp)->n_fhp->nfh_len, 0);
8589 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
8590 *tl = txdr_unsigned(NFSV4OP_COPY);
8591 nfsm_stateidtom(nd, instateidp, NFSSTATEID_PUTSTATEID);
8592 nfsm_stateidtom(nd, outstateidp, NFSSTATEID_PUTSTATEID);
8593 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_HYPER + 4 * NFSX_UNSIGNED);
8594 txdr_hyper(inoff, tl); tl += 2;
8595 txdr_hyper(outoff, tl); tl += 2;
8596 txdr_hyper(len, tl); tl += 2;
8597 if (consecutive)
8598 *tl++ = newnfs_true;
8599 else
8600 *tl++ = newnfs_false;
8601 *tl++ = newnfs_true;
8602 *tl++ = 0;
8603 *tl = txdr_unsigned(NFSV4OP_GETATTR);
8604 NFSWRITEGETATTR_ATTRBIT(&attrbits);
8605 nfsrv_putattrbit(nd, &attrbits);
8606 error = nfscl_request(nd, invp, p, cred);
8607 if (error != 0)
8608 return (error);
8609 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
8610 /* Get the input file's attributes. */
8611 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
8612 if (*(tl + 1) == 0) {
8613 error = nfsm_loadattr(nd, innap);
8614 if (error != 0)
8615 goto nfsmout;
8616 *inattrflagp = 1;
8617 } else
8618 nd->nd_flag |= ND_NOMOREDATA;
8619 }
8620 /* Skip over return stat for PutFH. */
8621 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
8622 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
8623 if (*++tl != 0)
8624 nd->nd_flag |= ND_NOMOREDATA;
8625 }
8626 /* Skip over return stat for Copy. */
8627 if ((nd->nd_flag & ND_NOMOREDATA) == 0)
8628 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
8629 if (nd->nd_repstat == 0) {
8630 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
8631 if (*tl != 0) {
8632 /* There should be no callback ids. */
8633 error = NFSERR_BADXDR;
8634 goto nfsmout;
8635 }
8636 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED +
8637 NFSX_VERF);
8638 len = fxdr_hyper(tl); tl += 2;
8639 *commitp = fxdr_unsigned(int, *tl++);
8640 NFSLOCKMNT(nmp);
8641 if (!NFSHASWRITEVERF(nmp)) {
8642 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
8643 NFSSETWRITEVERF(nmp);
8644 } else if (NFSBCMP(tl, nmp->nm_verf, NFSX_VERF)) {
8645 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
8646 nd->nd_repstat = NFSERR_STALEWRITEVERF;
8647 }
8648 NFSUNLOCKMNT(nmp);
8649 tl += (NFSX_VERF / NFSX_UNSIGNED);
8650 if (nd->nd_repstat == 0 && *++tl != newnfs_true)
8651 /* Must be a synchronous copy. */
8652 nd->nd_repstat = NFSERR_NOTSUPP;
8653 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
8654 error = nfsm_loadattr(nd, outnap);
8655 if (error == 0)
8656 *outattrflagp = NFS_LATTR_NOSHRINK;
8657 if (nd->nd_repstat == 0)
8658 *lenp = len;
8659 } else if (nd->nd_repstat == NFSERR_OFFLOADNOREQS) {
8660 /*
8661 * For the case where consecutive is not supported, but
8662 * synchronous is supported, we can try consecutive == false
8663 * by returning this error. Otherwise, return NFSERR_NOTSUPP,
8664 * since Copy cannot be done.
8665 */
8666 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
8667 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
8668 if (!consecutive || *++tl == newnfs_false)
8669 nd->nd_repstat = NFSERR_NOTSUPP;
8670 } else
8671 nd->nd_repstat = NFSERR_BADXDR;
8672 }
8673 if (error == 0)
8674 error = nd->nd_repstat;
8675 nfsmout:
8676 m_freem(nd->nd_mrep);
8677 return (error);
8678 }
8679
8680 /*
8681 * Seek operation.
8682 */
8683 int
8684 nfsrpc_seek(vnode_t vp, off_t *offp, bool *eofp, int content,
8685 struct ucred *cred, struct nfsvattr *nap, int *attrflagp)
8686 {
8687 int error, expireret = 0, retrycnt;
8688 u_int32_t clidrev = 0;
8689 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
8690 struct nfsnode *np = VTONFS(vp);
8691 struct nfsfh *nfhp = NULL;
8692 nfsv4stateid_t stateid;
8693 void *lckp;
8694
8695 if (nmp->nm_clp != NULL)
8696 clidrev = nmp->nm_clp->nfsc_clientidrev;
8697 nfhp = np->n_fhp;
8698 retrycnt = 0;
8699 do {
8700 lckp = NULL;
8701 nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
8702 NFSV4OPEN_ACCESSREAD, 0, cred, curthread, &stateid, &lckp);
8703 error = nfsrpc_seekrpc(vp, offp, &stateid, eofp, content,
8704 nap, attrflagp, cred);
8705 if (error == NFSERR_STALESTATEID)
8706 nfscl_initiate_recovery(nmp->nm_clp);
8707 if (lckp != NULL)
8708 nfscl_lockderef(lckp);
8709 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
8710 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
8711 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
8712 (void) nfs_catnap(PZERO, error, "nfs_seek");
8713 } else if ((error == NFSERR_EXPIRED || (!NFSHASINT(nmp) &&
8714 error == NFSERR_BADSTATEID)) && clidrev != 0) {
8715 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev,
8716 curthread);
8717 } else if (error == NFSERR_BADSTATEID && NFSHASINT(nmp)) {
8718 error = EIO;
8719 }
8720 retrycnt++;
8721 } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
8722 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
8723 error == NFSERR_BADSESSION ||
8724 (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
8725 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
8726 expireret == 0 && clidrev != 0 && retrycnt < 4) ||
8727 (error == NFSERR_OPENMODE && retrycnt < 4));
8728 if (error && retrycnt >= 4)
8729 error = EIO;
8730 return (error);
8731 }
8732
8733 /*
8734 * The seek RPC.
8735 */
8736 static int
8737 nfsrpc_seekrpc(vnode_t vp, off_t *offp, nfsv4stateid_t *stateidp, bool *eofp,
8738 int content, struct nfsvattr *nap, int *attrflagp, struct ucred *cred)
8739 {
8740 uint32_t *tl;
8741 int error;
8742 struct nfsrv_descript nfsd;
8743 struct nfsrv_descript *nd = &nfsd;
8744 nfsattrbit_t attrbits;
8745
8746 *attrflagp = 0;
8747 NFSCL_REQSTART(nd, NFSPROC_SEEK, vp, cred);
8748 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
8749 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
8750 txdr_hyper(*offp, tl); tl += 2;
8751 *tl++ = txdr_unsigned(content);
8752 *tl = txdr_unsigned(NFSV4OP_GETATTR);
8753 NFSGETATTR_ATTRBIT(&attrbits);
8754 nfsrv_putattrbit(nd, &attrbits);
8755 error = nfscl_request(nd, vp, curthread, cred);
8756 if (error != 0)
8757 return (error);
8758 if (nd->nd_repstat == 0) {
8759 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_HYPER);
8760 if (*tl++ == newnfs_true)
8761 *eofp = true;
8762 else
8763 *eofp = false;
8764 *offp = fxdr_hyper(tl);
8765 /* Just skip over Getattr op status. */
8766 error = nfsm_loadattr(nd, nap);
8767 if (error == 0)
8768 *attrflagp = 1;
8769 }
8770 error = nd->nd_repstat;
8771 nfsmout:
8772 m_freem(nd->nd_mrep);
8773 return (error);
8774 }
8775
8776 /*
8777 * The getextattr RPC.
8778 */
8779 int
8780 nfsrpc_getextattr(vnode_t vp, const char *name, struct uio *uiop, ssize_t *lenp,
8781 struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p)
8782 {
8783 uint32_t *tl;
8784 int error;
8785 struct nfsrv_descript nfsd;
8786 struct nfsrv_descript *nd = &nfsd;
8787 nfsattrbit_t attrbits;
8788 uint32_t len, len2;
8789
8790 *attrflagp = 0;
8791 NFSCL_REQSTART(nd, NFSPROC_GETEXTATTR, vp, cred);
8792 nfsm_strtom(nd, name, strlen(name));
8793 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
8794 *tl = txdr_unsigned(NFSV4OP_GETATTR);
8795 NFSGETATTR_ATTRBIT(&attrbits);
8796 nfsrv_putattrbit(nd, &attrbits);
8797 error = nfscl_request(nd, vp, p, cred);
8798 if (error != 0)
8799 return (error);
8800 if (nd->nd_repstat == 0) {
8801 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
8802 len = fxdr_unsigned(uint32_t, *tl);
8803 /* Sanity check lengths. */
8804 if (uiop != NULL && len > 0 && len <= IOSIZE_MAX &&
8805 uiop->uio_resid <= UINT32_MAX) {
8806 len2 = uiop->uio_resid;
8807 if (len2 >= len)
8808 error = nfsm_mbufuio(nd, uiop, len);
8809 else {
8810 error = nfsm_mbufuio(nd, uiop, len2);
8811 if (error == 0) {
8812 /*
8813 * nfsm_mbufuio() advances to a multiple
8814 * of 4, so round up len2 as well. Then
8815 * we need to advance over the rest of
8816 * the data, rounding up the remaining
8817 * length.
8818 */
8819 len2 = NFSM_RNDUP(len2);
8820 len2 = NFSM_RNDUP(len - len2);
8821 if (len2 > 0)
8822 error = nfsm_advance(nd, len2,
8823 -1);
8824 }
8825 }
8826 } else if (uiop == NULL && len > 0) {
8827 /* Just wants the length and not the data. */
8828 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
8829 } else if (len > 0)
8830 error = ENOATTR;
8831 if (error != 0)
8832 goto nfsmout;
8833 *lenp = len;
8834 /* Just skip over Getattr op status. */
8835 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
8836 error = nfsm_loadattr(nd, nap);
8837 if (error == 0)
8838 *attrflagp = 1;
8839 }
8840 if (error == 0)
8841 error = nd->nd_repstat;
8842 nfsmout:
8843 m_freem(nd->nd_mrep);
8844 return (error);
8845 }
8846
8847 /*
8848 * The setextattr RPC.
8849 */
8850 int
8851 nfsrpc_setextattr(vnode_t vp, const char *name, struct uio *uiop,
8852 struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p)
8853 {
8854 uint32_t *tl;
8855 int error;
8856 struct nfsrv_descript nfsd;
8857 struct nfsrv_descript *nd = &nfsd;
8858 nfsattrbit_t attrbits;
8859
8860 *attrflagp = 0;
8861 NFSCL_REQSTART(nd, NFSPROC_SETEXTATTR, vp, cred);
8862 if (uiop->uio_resid > nd->nd_maxreq) {
8863 /* nd_maxreq is set by NFSCL_REQSTART(). */
8864 m_freem(nd->nd_mreq);
8865 return (EINVAL);
8866 }
8867 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
8868 *tl = txdr_unsigned(NFSV4SXATTR_EITHER);
8869 nfsm_strtom(nd, name, strlen(name));
8870 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
8871 *tl = txdr_unsigned(uiop->uio_resid);
8872 nfsm_uiombuf(nd, uiop, uiop->uio_resid);
8873 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
8874 *tl = txdr_unsigned(NFSV4OP_GETATTR);
8875 NFSGETATTR_ATTRBIT(&attrbits);
8876 nfsrv_putattrbit(nd, &attrbits);
8877 error = nfscl_request(nd, vp, p, cred);
8878 if (error != 0)
8879 return (error);
8880 if (nd->nd_repstat == 0) {
8881 /* Just skip over the reply and Getattr op status. */
8882 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + 3 *
8883 NFSX_UNSIGNED);
8884 error = nfsm_loadattr(nd, nap);
8885 if (error == 0)
8886 *attrflagp = 1;
8887 }
8888 if (error == 0)
8889 error = nd->nd_repstat;
8890 nfsmout:
8891 m_freem(nd->nd_mrep);
8892 return (error);
8893 }
8894
8895 /*
8896 * The removeextattr RPC.
8897 */
8898 int
8899 nfsrpc_rmextattr(vnode_t vp, const char *name, struct nfsvattr *nap,
8900 int *attrflagp, struct ucred *cred, NFSPROC_T *p)
8901 {
8902 uint32_t *tl;
8903 int error;
8904 struct nfsrv_descript nfsd;
8905 struct nfsrv_descript *nd = &nfsd;
8906 nfsattrbit_t attrbits;
8907
8908 *attrflagp = 0;
8909 NFSCL_REQSTART(nd, NFSPROC_RMEXTATTR, vp, cred);
8910 nfsm_strtom(nd, name, strlen(name));
8911 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
8912 *tl = txdr_unsigned(NFSV4OP_GETATTR);
8913 NFSGETATTR_ATTRBIT(&attrbits);
8914 nfsrv_putattrbit(nd, &attrbits);
8915 error = nfscl_request(nd, vp, p, cred);
8916 if (error != 0)
8917 return (error);
8918 if (nd->nd_repstat == 0) {
8919 /* Just skip over the reply and Getattr op status. */
8920 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + 3 *
8921 NFSX_UNSIGNED);
8922 error = nfsm_loadattr(nd, nap);
8923 if (error == 0)
8924 *attrflagp = 1;
8925 }
8926 if (error == 0)
8927 error = nd->nd_repstat;
8928 nfsmout:
8929 m_freem(nd->nd_mrep);
8930 return (error);
8931 }
8932
8933 /*
8934 * The listextattr RPC.
8935 */
8936 int
8937 nfsrpc_listextattr(vnode_t vp, uint64_t *cookiep, struct uio *uiop,
8938 size_t *lenp, bool *eofp, struct nfsvattr *nap, int *attrflagp,
8939 struct ucred *cred, NFSPROC_T *p)
8940 {
8941 uint32_t *tl;
8942 int cnt, error, i, len;
8943 struct nfsrv_descript nfsd;
8944 struct nfsrv_descript *nd = &nfsd;
8945 nfsattrbit_t attrbits;
8946 u_char c;
8947
8948 *attrflagp = 0;
8949 NFSCL_REQSTART(nd, NFSPROC_LISTEXTATTR, vp, cred);
8950 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
8951 txdr_hyper(*cookiep, tl); tl += 2;
8952 *tl++ = txdr_unsigned(*lenp);
8953 *tl = txdr_unsigned(NFSV4OP_GETATTR);
8954 NFSGETATTR_ATTRBIT(&attrbits);
8955 nfsrv_putattrbit(nd, &attrbits);
8956 error = nfscl_request(nd, vp, p, cred);
8957 if (error != 0)
8958 return (error);
8959 *eofp = true;
8960 *lenp = 0;
8961 if (nd->nd_repstat == 0) {
8962 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
8963 *cookiep = fxdr_hyper(tl); tl += 2;
8964 cnt = fxdr_unsigned(int, *tl);
8965 if (cnt < 0) {
8966 error = EBADRPC;
8967 goto nfsmout;
8968 }
8969 for (i = 0; i < cnt; i++) {
8970 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
8971 len = fxdr_unsigned(int, *tl);
8972 if (len <= 0 || len > EXTATTR_MAXNAMELEN) {
8973 error = EBADRPC;
8974 goto nfsmout;
8975 }
8976 if (uiop == NULL)
8977 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
8978 else if (uiop->uio_resid >= len + 1) {
8979 c = len;
8980 error = uiomove(&c, sizeof(c), uiop);
8981 if (error == 0)
8982 error = nfsm_mbufuio(nd, uiop, len);
8983 } else {
8984 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
8985 *eofp = false;
8986 }
8987 if (error != 0)
8988 goto nfsmout;
8989 *lenp += (len + 1);
8990 }
8991 /* Get the eof and skip over the Getattr op status. */
8992 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED);
8993 /*
8994 * *eofp is set false above, because it wasn't able to copy
8995 * all of the reply.
8996 */
8997 if (*eofp && *tl == 0)
8998 *eofp = false;
8999 error = nfsm_loadattr(nd, nap);
9000 if (error == 0)
9001 *attrflagp = 1;
9002 }
9003 if (error == 0)
9004 error = nd->nd_repstat;
9005 nfsmout:
9006 m_freem(nd->nd_mrep);
9007 return (error);
9008 }
9009
9010 /*
9011 * Split an mbuf list. For non-M_EXTPG mbufs, just use m_split().
9012 */
9013 static struct mbuf *
9014 nfsm_split(struct mbuf *mp, uint64_t xfer)
9015 {
9016 struct mbuf *m, *m2;
9017 vm_page_t pg;
9018 int i, j, left, pgno, plen, trim;
9019 char *cp, *cp2;
9020
9021 if ((mp->m_flags & M_EXTPG) == 0) {
9022 m = m_split(mp, xfer, M_WAITOK);
9023 return (m);
9024 }
9025
9026 /* Find the correct mbuf to split at. */
9027 for (m = mp; m != NULL && xfer > m->m_len; m = m->m_next)
9028 xfer -= m->m_len;
9029 if (m == NULL)
9030 return (NULL);
9031
9032 /* If xfer == m->m_len, we can just split the mbuf list. */
9033 if (xfer == m->m_len) {
9034 m2 = m->m_next;
9035 m->m_next = NULL;
9036 return (m2);
9037 }
9038
9039 /* Find the page to split at. */
9040 pgno = 0;
9041 left = xfer;
9042 do {
9043 if (pgno == 0)
9044 plen = m_epg_pagelen(m, 0, m->m_epg_1st_off);
9045 else
9046 plen = m_epg_pagelen(m, pgno, 0);
9047 if (left <= plen)
9048 break;
9049 left -= plen;
9050 pgno++;
9051 } while (pgno < m->m_epg_npgs);
9052 if (pgno == m->m_epg_npgs)
9053 panic("nfsm_split: eroneous ext_pgs mbuf");
9054
9055 m2 = mb_alloc_ext_pgs(M_WAITOK, mb_free_mext_pgs);
9056 m2->m_epg_flags |= EPG_FLAG_ANON;
9057
9058 /*
9059 * If left < plen, allocate a new page for the new mbuf
9060 * and copy the data after left in the page to this new
9061 * page.
9062 */
9063 if (left < plen) {
9064 pg = vm_page_alloc_noobj(VM_ALLOC_WAITOK | VM_ALLOC_NODUMP |
9065 VM_ALLOC_WIRED);
9066 m2->m_epg_pa[0] = VM_PAGE_TO_PHYS(pg);
9067 m2->m_epg_npgs = 1;
9068
9069 /* Copy the data after left to the new page. */
9070 trim = plen - left;
9071 cp = (char *)(void *)PHYS_TO_DMAP(m->m_epg_pa[pgno]);
9072 if (pgno == 0)
9073 cp += m->m_epg_1st_off;
9074 cp += left;
9075 cp2 = (char *)(void *)PHYS_TO_DMAP(m2->m_epg_pa[0]);
9076 if (pgno == m->m_epg_npgs - 1)
9077 m2->m_epg_last_len = trim;
9078 else {
9079 cp2 += PAGE_SIZE - trim;
9080 m2->m_epg_1st_off = PAGE_SIZE - trim;
9081 m2->m_epg_last_len = m->m_epg_last_len;
9082 }
9083 memcpy(cp2, cp, trim);
9084 m2->m_len = trim;
9085 } else {
9086 m2->m_len = 0;
9087 m2->m_epg_last_len = m->m_epg_last_len;
9088 }
9089
9090 /* Move the pages beyond pgno to the new mbuf. */
9091 for (i = pgno + 1, j = m2->m_epg_npgs; i < m->m_epg_npgs; i++, j++) {
9092 m2->m_epg_pa[j] = m->m_epg_pa[i];
9093 /* Never moves page 0. */
9094 m2->m_len += m_epg_pagelen(m, i, 0);
9095 }
9096 m2->m_epg_npgs = j;
9097 m->m_epg_npgs = pgno + 1;
9098 m->m_epg_last_len = left;
9099 m->m_len = xfer;
9100
9101 m2->m_next = m->m_next;
9102 m->m_next = NULL;
9103 return (m2);
9104 }
9105
9106 /*
9107 * Do the NFSv4.1 Bind Connection to Session.
9108 * Called from the reconnect layer of the krpc (sys/rpc/clnt_rc.c).
9109 */
9110 void
9111 nfsrpc_bindconnsess(CLIENT *cl, void *arg, struct ucred *cr)
9112 {
9113 struct nfscl_reconarg *rcp = (struct nfscl_reconarg *)arg;
9114 uint32_t res, *tl;
9115 struct nfsrv_descript nfsd;
9116 struct nfsrv_descript *nd = &nfsd;
9117 struct rpc_callextra ext;
9118 struct timeval utimeout;
9119 enum clnt_stat stat;
9120 int error;
9121
9122 nfscl_reqstart(nd, NFSPROC_BINDCONNTOSESS, NULL, NULL, 0, NULL, NULL,
9123 NFS_VER4, rcp->minorvers, NULL);
9124 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED);
9125 memcpy(tl, rcp->sessionid, NFSX_V4SESSIONID);
9126 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
9127 *tl++ = txdr_unsigned(NFSCDFC4_FORE_OR_BOTH);
9128 *tl = newnfs_false;
9129
9130 memset(&ext, 0, sizeof(ext));
9131 utimeout.tv_sec = 30;
9132 utimeout.tv_usec = 0;
9133 ext.rc_auth = authunix_create(cr);
9134 nd->nd_mrep = NULL;
9135 stat = CLNT_CALL_MBUF(cl, &ext, NFSV4PROC_COMPOUND, nd->nd_mreq,
9136 &nd->nd_mrep, utimeout);
9137 AUTH_DESTROY(ext.rc_auth);
9138 if (stat != RPC_SUCCESS) {
9139 printf("nfsrpc_bindconnsess: call failed stat=%d\n", stat);
9140 return;
9141 }
9142 if (nd->nd_mrep == NULL) {
9143 printf("nfsrpc_bindconnsess: no reply args\n");
9144 return;
9145 }
9146 error = 0;
9147 newnfs_realign(&nd->nd_mrep, M_WAITOK);
9148 nd->nd_md = nd->nd_mrep;
9149 nd->nd_dpos = mtod(nd->nd_md, char *);
9150 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
9151 nd->nd_repstat = fxdr_unsigned(uint32_t, *tl++);
9152 if (nd->nd_repstat == NFSERR_OK) {
9153 res = fxdr_unsigned(uint32_t, *tl);
9154 if (res > 0 && (error = nfsm_advance(nd, NFSM_RNDUP(res),
9155 -1)) != 0)
9156 goto nfsmout;
9157 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID +
9158 4 * NFSX_UNSIGNED);
9159 tl += 3;
9160 if (!NFSBCMP(tl, rcp->sessionid, NFSX_V4SESSIONID)) {
9161 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
9162 res = fxdr_unsigned(uint32_t, *tl);
9163 if (res != NFSCDFS4_BOTH)
9164 printf("nfsrpc_bindconnsess: did not "
9165 "return FS4_BOTH\n");
9166 } else
9167 printf("nfsrpc_bindconnsess: not same "
9168 "sessionid\n");
9169 } else if (nd->nd_repstat != NFSERR_BADSESSION)
9170 printf("nfsrpc_bindconnsess: returned %d\n", nd->nd_repstat);
9171 nfsmout:
9172 if (error != 0)
9173 printf("nfsrpc_bindconnsess: reply bad xdr\n");
9174 m_freem(nd->nd_mrep);
9175 }
Cache object: 48474d18ead98622a208cc2de1aafd8a
|