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