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