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