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