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