kernel - Fix endless nfs error 70 during shutdown
[dragonfly.git] / sys / vfs / nfs / nfsm_subs.c
CommitLineData
e97453f3
MD
1/*
2 * Copyright (c) 2009 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34/*
35 * Copyright (c) 1989, 1993
36 * The Regents of the University of California. All rights reserved.
37 *
38 * This code is derived from software contributed to Berkeley by
39 * Rick Macklem at The University of Guelph.
40 *
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
43 * are met:
44 * 1. Redistributions of source code must retain the above copyright
45 * notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 * notice, this list of conditions and the following disclaimer in the
48 * documentation and/or other materials provided with the distribution.
49 * 3. All advertising materials mentioning features or use of this software
50 * must display the following acknowledgement:
51 * This product includes software developed by the University of
52 * California, Berkeley and its contributors.
53 * 4. Neither the name of the University nor the names of its contributors
54 * may be used to endorse or promote products derived from this software
55 * without specific prior written permission.
56 *
57 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
58 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
59 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
60 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
61 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
62 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
63 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
64 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
65 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
66 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
67 * SUCH DAMAGE.
68 */
69
70/*
71 * These functions support the macros and help fiddle mbuf chains for
72 * the nfs op functions. They do things like create the rpc header and
73 * copy data between mbuf chains and uio lists.
74 */
75#include <sys/param.h>
76#include <sys/systm.h>
77#include <sys/kernel.h>
78#include <sys/buf.h>
79#include <sys/proc.h>
80#include <sys/mount.h>
81#include <sys/vnode.h>
82#include <sys/nlookup.h>
83#include <sys/namei.h>
84#include <sys/mbuf.h>
85#include <sys/socket.h>
86#include <sys/stat.h>
87#include <sys/malloc.h>
88#include <sys/sysent.h>
89#include <sys/syscall.h>
90#include <sys/conf.h>
91#include <sys/objcache.h>
92
93#include <vm/vm.h>
94#include <vm/vm_object.h>
95#include <vm/vm_extern.h>
e97453f3
MD
96
97#include <sys/buf2.h>
98
99#include "rpcv2.h"
100#include "nfsproto.h"
101#include "nfs.h"
102#include "nfsmount.h"
103#include "nfsnode.h"
104#include "xdr_subs.h"
105#include "nfsm_subs.h"
106#include "nfsrtt.h"
107
108#include <netinet/in.h>
109
110static u_int32_t nfs_xid = 0;
111
112/*
113 * Create the header for an rpc request packet
114 * The hsiz is the size of the rest of the nfs request header.
115 * (just used to decide if a cluster is a good idea)
116 */
42edf14f
MD
117void
118nfsm_reqhead(nfsm_info_t info, struct vnode *vp, u_long procid, int hsiz)
e97453f3 119{
42edf14f
MD
120 info->mb = m_getl(hsiz, MB_WAIT, MT_DATA, 0, NULL);
121 info->mb->m_len = 0;
122 info->mreq = info->mb;
123 info->bpos = mtod(info->mb, caddr_t);
e97453f3
MD
124}
125
126/*
127 * Build the RPC header and fill in the authorization info.
128 * The authorization string argument is only used when the credentials
129 * come from outside of the kernel.
130 * Returns the head of the mbuf list.
131 */
132struct mbuf *
133nfsm_rpchead(struct ucred *cr, int nmflag, int procid, int auth_type,
134 int auth_len, char *auth_str, int verf_len, char *verf_str,
135 struct mbuf *mrest, int mrest_len, struct mbuf **mbp,
136 u_int32_t *xidp)
137{
42edf14f 138 struct nfsm_info info;
c16c1c4b 139 struct mbuf *mb2;
e97453f3 140 u_int32_t *tl;
96f9dac1 141 u_int32_t xid;
e97453f3 142 int siz, grpsiz, authsiz, dsiz;
42edf14f 143 int i;
e97453f3
MD
144
145 authsiz = nfsm_rndup(auth_len);
146 dsiz = authsiz + 10 * NFSX_UNSIGNED;
42edf14f 147 info.mb = m_getl(dsiz, MB_WAIT, MT_DATA, M_PKTHDR, NULL);
e97453f3
MD
148 if (dsiz < MINCLSIZE) {
149 if (dsiz < MHLEN)
42edf14f 150 MH_ALIGN(info.mb, dsiz);
e97453f3 151 else
42edf14f 152 MH_ALIGN(info.mb, 8 * NFSX_UNSIGNED);
e97453f3 153 }
42edf14f
MD
154 info.mb->m_len = info.mb->m_pkthdr.len = 0;
155 info.mreq = info.mb;
156 info.bpos = mtod(info.mb, caddr_t);
e97453f3
MD
157
158 /*
159 * First the RPC header.
160 */
42edf14f 161 tl = nfsm_build(&info, 8 * NFSX_UNSIGNED);
e97453f3
MD
162
163 /* Get a pretty random xid to start with */
164 if (!nfs_xid)
165 nfs_xid = krandom();
e97453f3 166
96f9dac1
MD
167 do {
168 xid = atomic_fetchadd_int(&nfs_xid, 1);
169 } while (xid == 0);
170
171 *tl++ = *xidp = txdr_unsigned(xid);
e97453f3
MD
172 *tl++ = rpc_call;
173 *tl++ = rpc_vers;
174 *tl++ = txdr_unsigned(NFS_PROG);
175 if (nmflag & NFSMNT_NFSV3)
176 *tl++ = txdr_unsigned(NFS_VER3);
177 else
178 *tl++ = txdr_unsigned(NFS_VER2);
179 if (nmflag & NFSMNT_NFSV3)
180 *tl++ = txdr_unsigned(procid);
181 else
182 *tl++ = txdr_unsigned(nfsv2_procid[procid]);
183
184 /*
185 * And then the authorization cred.
186 */
187 *tl++ = txdr_unsigned(auth_type);
188 *tl = txdr_unsigned(authsiz);
189 switch (auth_type) {
190 case RPCAUTH_UNIX:
42edf14f 191 tl = nfsm_build(&info, auth_len);
e97453f3
MD
192 *tl++ = 0; /* stamp ?? */
193 *tl++ = 0; /* NULL hostname */
194 *tl++ = txdr_unsigned(cr->cr_uid);
195 *tl++ = txdr_unsigned(cr->cr_groups[0]);
196 grpsiz = (auth_len >> 2) - 5;
197 *tl++ = txdr_unsigned(grpsiz);
198 for (i = 1; i <= grpsiz; i++)
199 *tl++ = txdr_unsigned(cr->cr_groups[i]);
200 break;
201 case RPCAUTH_KERB4:
202 siz = auth_len;
203 while (siz > 0) {
42edf14f 204 if (M_TRAILINGSPACE(info.mb) == 0) {
c16c1c4b
MD
205 mb2 = m_getl(siz, MB_WAIT, MT_DATA, 0, NULL);
206 mb2->m_len = 0;
207 info.mb->m_next = mb2;
208 info.mb = mb2;
42edf14f 209 info.bpos = mtod(info.mb, caddr_t);
e97453f3 210 }
42edf14f
MD
211 i = min(siz, M_TRAILINGSPACE(info.mb));
212 bcopy(auth_str, info.bpos, i);
213 info.mb->m_len += i;
e97453f3 214 auth_str += i;
42edf14f 215 info.bpos += i;
e97453f3
MD
216 siz -= i;
217 }
218 if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
219 for (i = 0; i < siz; i++)
42edf14f
MD
220 *info.bpos++ = '\0';
221 info.mb->m_len += siz;
e97453f3
MD
222 }
223 break;
224 };
225
226 /*
227 * And the verifier...
228 */
42edf14f 229 tl = nfsm_build(&info, 2 * NFSX_UNSIGNED);
e97453f3
MD
230 if (verf_str) {
231 *tl++ = txdr_unsigned(RPCAUTH_KERB4);
232 *tl = txdr_unsigned(verf_len);
233 siz = verf_len;
234 while (siz > 0) {
42edf14f 235 if (M_TRAILINGSPACE(info.mb) == 0) {
c16c1c4b 236 mb2 = m_getl(siz, MB_WAIT, MT_DATA,
42edf14f 237 0, NULL);
c16c1c4b
MD
238 mb2->m_len = 0;
239 info.mb->m_next = mb2;
240 info.mb = mb2;
42edf14f 241 info.bpos = mtod(info.mb, caddr_t);
e97453f3 242 }
42edf14f
MD
243 i = min(siz, M_TRAILINGSPACE(info.mb));
244 bcopy(verf_str, info.bpos, i);
245 info.mb->m_len += i;
e97453f3 246 verf_str += i;
42edf14f 247 info.bpos += i;
e97453f3
MD
248 siz -= i;
249 }
250 if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
251 for (i = 0; i < siz; i++)
42edf14f
MD
252 *info.bpos++ = '\0';
253 info.mb->m_len += siz;
e97453f3
MD
254 }
255 } else {
256 *tl++ = txdr_unsigned(RPCAUTH_NULL);
257 *tl = 0;
258 }
42edf14f
MD
259 info.mb->m_next = mrest;
260 info.mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
261 info.mreq->m_pkthdr.rcvif = NULL;
262 *mbp = info.mb;
263 return (info.mreq);
264}
265
266void *
267nfsm_build(nfsm_info_t info, int bytes)
268{
c16c1c4b 269 struct mbuf *mb2;
42edf14f
MD
270 void *ptr;
271
272 if (bytes > M_TRAILINGSPACE(info->mb)) {
c16c1c4b 273 MGET(mb2, MB_WAIT, MT_DATA);
42edf14f
MD
274 if (bytes > MLEN)
275 panic("build > MLEN");
c16c1c4b
MD
276 info->mb->m_next = mb2;
277 info->mb = mb2;
42edf14f
MD
278 info->mb->m_len = 0;
279 info->bpos = mtod(info->mb, caddr_t);
280 }
281 ptr = info->bpos;
282 info->mb->m_len += bytes;
283 info->bpos += bytes;
284 return (ptr);
285}
286
287/*
288 *
289 * If NULL returned caller is expected to abort with an EBADRPC error.
290 * Caller will usually use the NULLOUT macro.
291 */
292void *
293nfsm_dissect(nfsm_info_t info, int bytes)
294{
295 caddr_t cp2;
296 void *ptr;
297 int error;
298 int n;
299
300 n = mtod(info->md, caddr_t) + info->md->m_len - info->dpos;
301 if (bytes <= n) {
302 ptr = info->dpos;
303 info->dpos += bytes;
304 } else {
305 error = nfsm_disct(&info->md, &info->dpos, bytes, n, &cp2);
306 if (error) {
307 m_freem(info->mrep);
308 info->mrep = NULL;
309 ptr = NULL;
310 } else {
311 ptr = cp2;
312 }
313 }
314 return (ptr);
315}
316
317/*
318 *
319 * Caller is expected to abort if non-zero error is returned.
320 */
321int
322nfsm_fhtom(nfsm_info_t info, struct vnode *vp)
323{
324 u_int32_t *tl;
325 caddr_t cp;
326 int error;
327 int n;
328
329 if (info->v3) {
330 n = nfsm_rndup(VTONFS(vp)->n_fhsize) + NFSX_UNSIGNED;
331 if (n <= M_TRAILINGSPACE(info->mb)) {
332 tl = nfsm_build(info, n);
333 *tl++ = txdr_unsigned(VTONFS(vp)->n_fhsize);
334 *(tl + ((n >> 2) - 2)) = 0;
335 bcopy((caddr_t)VTONFS(vp)->n_fhp,(caddr_t)tl,
336 VTONFS(vp)->n_fhsize);
337 error = 0;
338 } else if ((error = nfsm_strtmbuf(&info->mb, &info->bpos,
339 (caddr_t)VTONFS(vp)->n_fhp,
340 VTONFS(vp)->n_fhsize)) != 0) {
341 m_freem(info->mreq);
342 info->mreq = NULL;
343 }
344 } else {
345 cp = nfsm_build(info, NFSX_V2FH);
346 bcopy(VTONFS(vp)->n_fhp, cp, NFSX_V2FH);
347 error = 0;
348 }
349 return (error);
350}
351
352void
353nfsm_srvfhtom(nfsm_info_t info, fhandle_t *fhp)
354{
355 u_int32_t *tl;
356
357 if (info->v3) {
358 tl = nfsm_build(info, NFSX_UNSIGNED + NFSX_V3FH);
359 *tl++ = txdr_unsigned(NFSX_V3FH);
360 bcopy(fhp, tl, NFSX_V3FH);
361 } else {
362 tl = nfsm_build(info, NFSX_V2FH);
363 bcopy(fhp, tl, NFSX_V2FH);
364 }
365}
366
367void
368nfsm_srvpostop_fh(nfsm_info_t info, fhandle_t *fhp)
369{
370 u_int32_t *tl;
371
372 tl = nfsm_build(info, 2 * NFSX_UNSIGNED + NFSX_V3FH);
373 *tl++ = nfs_true;
374 *tl++ = txdr_unsigned(NFSX_V3FH);
375 bcopy(fhp, tl, NFSX_V3FH);
376}
377
378/*
379 * Caller is expected to abort if non-zero error is returned.
380 *
381 * NOTE: (*vpp) may be loaded with a valid vnode even if (*gotvpp)
382 * winds up 0. The caller is responsible for dealing with (*vpp).
383 */
384int
385nfsm_mtofh(nfsm_info_t info, struct vnode *dvp, struct vnode **vpp, int *gotvpp)
386{
387 struct nfsnode *ttnp;
388 nfsfh_t *ttfhp;
389 u_int32_t *tl;
390 int ttfhsize;
391 int error = 0;
392
393 if (info->v3) {
394 tl = nfsm_dissect(info, NFSX_UNSIGNED);
395 if (tl == NULL)
396 return(EBADRPC);
397 *gotvpp = fxdr_unsigned(int, *tl);
398 } else {
399 *gotvpp = 1;
400 }
401 if (*gotvpp) {
402 NEGATIVEOUT(ttfhsize = nfsm_getfh(info, &ttfhp));
403 error = nfs_nget(dvp->v_mount, ttfhp, ttfhsize, &ttnp);
404 if (error) {
405 m_freem(info->mrep);
406 info->mrep = NULL;
407 return (error);
408 }
409 *vpp = NFSTOV(ttnp);
410 }
411 if (info->v3) {
412 tl = nfsm_dissect(info, NFSX_UNSIGNED);
413 if (tl == NULL)
414 return (EBADRPC);
415 if (*gotvpp) {
416 *gotvpp = fxdr_unsigned(int, *tl);
417 } else if (fxdr_unsigned(int, *tl)) {
418 error = nfsm_adv(info, NFSX_V3FATTR);
419 if (error)
420 return (error);
421 }
422 }
423 if (*gotvpp)
424 error = nfsm_loadattr(info, *vpp, NULL);
425nfsmout:
426 return (error);
427}
428
429/*
430 *
431 * Caller is expected to abort with EBADRPC if a negative length is returned.
432 */
433int
434nfsm_getfh(nfsm_info_t info, nfsfh_t **fhpp)
435{
436 u_int32_t *tl;
437 int n;
438
439 *fhpp = NULL;
440 if (info->v3) {
441 tl = nfsm_dissect(info, NFSX_UNSIGNED);
442 if (tl == NULL)
443 return(-1);
444 if ((n = fxdr_unsigned(int, *tl)) <= 0 || n > NFSX_V3FHMAX) {
445 m_freem(info->mrep);
446 info->mrep = NULL;
447 return(-1);
448 }
449 } else {
450 n = NFSX_V2FH;
451 }
452 *fhpp = nfsm_dissect(info, nfsm_rndup(n));
453 if (*fhpp == NULL)
454 return(-1);
455 return(n);
456}
457
458/*
459 * Caller is expected to abort if a non-zero error is returned.
460 */
461int
462nfsm_loadattr(nfsm_info_t info, struct vnode *vp, struct vattr *vap)
463{
464 int error;
465
466 error = nfs_loadattrcache(vp, &info->md, &info->dpos, vap, 0);
467 if (error) {
468 m_freem(info->mrep);
469 info->mrep = NULL;
470 return (error);
471 }
472 return (0);
473}
474
475/*
476 * Caller is expected to abort if a non-zero error is returned.
477 */
478int
479nfsm_postop_attr(nfsm_info_t info, struct vnode *vp, int *attrp, int lflags)
480{
481 u_int32_t *tl;
482 int error;
483
484 tl = nfsm_dissect(info, NFSX_UNSIGNED);
485 if (tl == NULL)
486 return(EBADRPC);
487 *attrp = fxdr_unsigned(int, *tl);
488 if (*attrp) {
489 error = nfs_loadattrcache(vp, &info->md, &info->dpos,
490 NULL, lflags);
491 if (error) {
492 *attrp = 0;
493 m_freem(info->mrep);
494 info->mrep = NULL;
495 return (error);
496 }
497 }
498 return (0);
499}
500
501/*
502 * Caller is expected to abort if a non-zero error is returned.
503 */
504int
505nfsm_wcc_data(nfsm_info_t info, struct vnode *vp, int *attrp)
506{
507 u_int32_t *tl;
508 int error;
509 int ttattrf;
510 int ttretf = 0;
511
512 tl = nfsm_dissect(info, NFSX_UNSIGNED);
513 if (tl == NULL)
514 return (EBADRPC);
515 if (*tl == nfs_true) {
516 tl = nfsm_dissect(info, 6 * NFSX_UNSIGNED);
517 if (tl == NULL)
518 return (EBADRPC);
519 if (*attrp) {
520 ttretf = (VTONFS(vp)->n_mtime ==
521 fxdr_unsigned(u_int32_t, *(tl + 2)));
522 if (ttretf == 0)
523 VTONFS(vp)->n_flag |= NRMODIFIED;
524 }
525 error = nfsm_postop_attr(info, vp, &ttattrf,
526 NFS_LATTR_NOSHRINK|NFS_LATTR_NOMTIMECHECK);
527 if (error)
528 return(error);
529 } else {
530 error = nfsm_postop_attr(info, vp, &ttattrf,
531 NFS_LATTR_NOSHRINK);
532 if (error)
533 return(error);
534 }
535 if (*attrp)
536 *attrp = ttretf;
537 else
538 *attrp = ttattrf;
539 return(0);
540}
541
542/*
543 * This function updates the attribute cache based on data returned in the
544 * NFS reply for NFS RPCs that modify the target file. If the RPC succeeds
545 * a 'before' and 'after' mtime is returned that allows us to determine if
546 * the new mtime attribute represents our modification or someone else's
547 * modification.
548 *
549 * The flag argument returns non-0 if the original times matched, zero if
550 * they did not match. NRMODIFIED is automatically set if the before time
551 * does not match the original n_mtime, and n_mtime is automatically updated
552 * to the new after time (by nfsm_postop_attr()).
553 *
554 * If full is true, set all fields, otherwise just set mode and time fields
555 */
556void
557nfsm_v3attrbuild(nfsm_info_t info, struct vattr *vap, int full)
558{
559 u_int32_t *tl;
560
561 if (vap->va_mode != (mode_t)VNOVAL) {
562 tl = nfsm_build(info, 2 * NFSX_UNSIGNED);
563 *tl++ = nfs_true;
564 *tl = txdr_unsigned(vap->va_mode);
565 } else {
566 tl = nfsm_build(info, NFSX_UNSIGNED);
567 *tl = nfs_false;
568 }
569 if (full && vap->va_uid != (uid_t)VNOVAL) {
570 tl = nfsm_build(info, 2 * NFSX_UNSIGNED);
571 *tl++ = nfs_true;
572 *tl = txdr_unsigned(vap->va_uid);
573 } else {
574 tl = nfsm_build(info, NFSX_UNSIGNED);
575 *tl = nfs_false;
576 }
577 if (full && vap->va_gid != (gid_t)VNOVAL) {
578 tl = nfsm_build(info, 2 * NFSX_UNSIGNED);
579 *tl++ = nfs_true;
580 *tl = txdr_unsigned(vap->va_gid);
581 } else {
582 tl = nfsm_build(info, NFSX_UNSIGNED);
583 *tl = nfs_false;
584 }
585 if (full && vap->va_size != VNOVAL) {
586 tl = nfsm_build(info, 3 * NFSX_UNSIGNED);
587 *tl++ = nfs_true;
588 txdr_hyper(vap->va_size, tl);
589 } else {
590 tl = nfsm_build(info, NFSX_UNSIGNED);
591 *tl = nfs_false;
592 }
593 if (vap->va_atime.tv_sec != VNOVAL) {
594 if (vap->va_atime.tv_sec != time_second) {
595 tl = nfsm_build(info, 3 * NFSX_UNSIGNED);
596 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
597 txdr_nfsv3time(&vap->va_atime, tl);
598 } else {
599 tl = nfsm_build(info, NFSX_UNSIGNED);
600 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
601 }
602 } else {
603 tl = nfsm_build(info, NFSX_UNSIGNED);
604 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
605 }
606 if (vap->va_mtime.tv_sec != VNOVAL) {
607 if (vap->va_mtime.tv_sec != time_second) {
608 tl = nfsm_build(info, 3 * NFSX_UNSIGNED);
609 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
610 txdr_nfsv3time(&vap->va_mtime, tl);
611 } else {
612 tl = nfsm_build(info, NFSX_UNSIGNED);
613 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
614 }
615 } else {
616 tl = nfsm_build(info, NFSX_UNSIGNED);
617 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
618 }
619}
620
621/*
622 * Caller is expected to abort with EBADRPC if a negative length is returned.
623 */
624int
625nfsm_strsiz(nfsm_info_t info, int maxlen)
626{
627 u_int32_t *tl;
628 int len;
629
630 tl = nfsm_dissect(info, NFSX_UNSIGNED);
631 if (tl == NULL)
632 return(-1);
633 len = fxdr_unsigned(int32_t, *tl);
634 if (len < 0 || len > maxlen)
635 return(-1);
636 return (len);
637}
638
639/*
640 * Caller is expected to abort if a negative length is returned, but also
641 * call nfsm_reply(0) if -2 is returned.
642 *
643 * This function sets *errorp. Caller should not modify the error code.
644 */
645int
646nfsm_srvstrsiz(nfsm_info_t info, int maxlen, int *errorp)
647{
648 u_int32_t *tl;
649 int len;
650
651 tl = nfsm_dissect(info, NFSX_UNSIGNED);
652 if (tl == NULL) {
653 *errorp = EBADRPC;
654 return(-1);
655 }
656 len = fxdr_unsigned(int32_t,*tl);
657 if (len > maxlen || len <= 0) {
658 *errorp = EBADRPC;
659 return(-2);
660 }
661 return(len);
662}
663
664/*
665 * Caller is expected to abort if a negative length is returned, but also
666 * call nfsm_reply(0) if -2 is returned.
667 *
668 * This function sets *errorp. Caller should not modify the error code.
669 */
670int
671nfsm_srvnamesiz(nfsm_info_t info, int *errorp)
672{
673 u_int32_t *tl;
674 int len;
675
676 tl = nfsm_dissect(info, NFSX_UNSIGNED);
677 if (tl == NULL) {
678 *errorp = EBADRPC;
679 return(-1);
680 }
681
682 /*
683 * In this case if *errorp is not EBADRPC and we are NFSv3,
684 * nfsm_reply() will not return a negative number. But all
685 * call cases assume len is valid so we really do want
686 * to return -1.
687 */
688 len = fxdr_unsigned(int32_t,*tl);
689 if (len > NFS_MAXNAMLEN)
690 *errorp = NFSERR_NAMETOL;
691 if (len <= 0)
692 *errorp = EBADRPC;
693 if (*errorp)
694 return(-2);
695 return (len);
696}
697
698/*
699 * Caller is expected to abort if a non-zero error is returned.
700 */
701int
702nfsm_mtouio(nfsm_info_t info, struct uio *uiop, int len)
703{
704 int error;
705
706 if (len > 0 &&
707 (error = nfsm_mbuftouio(&info->md, uiop, len, &info->dpos)) != 0) {
708 m_freem(info->mrep);
709 info->mrep = NULL;
710 return(error);
711 }
712 return(0);
713}
714
715/*
716 * Caller is expected to abort if a non-zero error is returned.
717 */
718int
edb90c22
MD
719nfsm_mtobio(nfsm_info_t info, struct bio *bio, int len)
720{
721 int error;
722
723 if (len > 0 &&
724 (error = nfsm_mbuftobio(&info->md, bio, len, &info->dpos)) != 0) {
725 m_freem(info->mrep);
726 info->mrep = NULL;
727 return(error);
728 }
729 return (0);
730}
731
732/*
733 * Caller is expected to abort if a non-zero error is returned.
734 */
735int
42edf14f
MD
736nfsm_uiotom(nfsm_info_t info, struct uio *uiop, int len)
737{
738 int error;
739
cc7d050e
MD
740 error = nfsm_uiotombuf(uiop, &info->mb, len, &info->bpos);
741 if (error) {
742 m_freem(info->mreq);
743 info->mreq = NULL;
744 return (error);
745 }
746 return(0);
747}
748
749int
750nfsm_biotom(nfsm_info_t info, struct bio *bio, int off, int len)
751{
752 int error;
753
754 error = nfsm_biotombuf(bio, &info->mb, off, len, &info->bpos);
755 if (error) {
42edf14f
MD
756 m_freem(info->mreq);
757 info->mreq = NULL;
758 return (error);
759 }
760 return(0);
761}
762
763/*
764 * Caller is expected to abort if a negative value is returned. This
765 * function sets *errorp. Caller should not modify the error code.
92540a7e
MD
766 *
767 * We load up the remaining info fields and run the request state
768 * machine until it is done.
edb90c22
MD
769 *
770 * This call runs the entire state machine and does not return until
771 * the command is complete.
42edf14f
MD
772 */
773int
774nfsm_request(nfsm_info_t info, struct vnode *vp, int procnum,
775 thread_t td, struct ucred *cred, int *errorp)
776{
92540a7e
MD
777 info->state = NFSM_STATE_SETUP;
778 info->procnum = procnum;
779 info->vp = vp;
780 info->td = td;
781 info->cred = cred;
edb90c22
MD
782 info->bio = NULL;
783 info->nmp = VFSTONFS(vp->v_mount);
92540a7e 784
edb90c22 785 *errorp = nfs_request(info, NFSM_STATE_SETUP, NFSM_STATE_DONE);
42edf14f
MD
786 if (*errorp) {
787 if ((*errorp & NFSERR_RETERR) == 0)
788 return(-1);
789 *errorp &= ~NFSERR_RETERR;
790 }
791 return(0);
792}
793
794/*
edb90c22
MD
795 * This call starts the state machine through the initial transmission.
796 * Completion is via the bio. The info structure must have installed
797 * a 'done' callback.
798 *
799 * If we are unable to do the initial tx we generate the bio completion
800 * ourselves.
801 */
802void
803nfsm_request_bio(nfsm_info_t info, struct vnode *vp, int procnum,
804 thread_t td, struct ucred *cred)
805{
806 struct buf *bp;
807 int error;
808
809 info->state = NFSM_STATE_SETUP;
810 info->procnum = procnum;
811 info->vp = vp;
812 info->td = td;
813 info->cred = cred;
edb90c22
MD
814 info->nmp = VFSTONFS(vp->v_mount);
815
816 error = nfs_request(info, NFSM_STATE_SETUP, NFSM_STATE_WAITREPLY);
817 if (error != EINPROGRESS) {
818 kprintf("nfsm_request_bio: early abort %d\n", error);
819 bp = info->bio->bio_buf;
83a03e7b 820 if (error) {
edb90c22 821 bp->b_flags |= B_ERROR;
83a03e7b
MD
822 if (error == EIO) /* unrecoverable */
823 bp->b_flags |= B_INVAL;
824 }
825
826 /*
827 * This can retry endlessly during a shutdown, change ESTALE
828 * to EIO in this case.
829 */
830 if (shutdown_inprog && error == ESTALE)
831 error = EIO;
edb90c22
MD
832 bp->b_error = error;
833 biodone(info->bio);
834 }
835}
836
837/*
42edf14f
MD
838 * Caller is expected to abort if a non-zero error is returned.
839 */
840int
841nfsm_strtom(nfsm_info_t info, const void *data, int len, int maxlen)
842{
843 u_int32_t *tl;
844 int error;
845 int n;
846
847 if (len > maxlen) {
848 m_freem(info->mreq);
849 info->mreq = NULL;
850 return(ENAMETOOLONG);
851 }
852 n = nfsm_rndup(len) + NFSX_UNSIGNED;
853 if (n <= M_TRAILINGSPACE(info->mb)) {
854 tl = nfsm_build(info, n);
855 *tl++ = txdr_unsigned(len);
856 *(tl + ((n >> 2) - 2)) = 0;
857 bcopy(data, tl, len);
858 error = 0;
859 } else {
860 error = nfsm_strtmbuf(&info->mb, &info->bpos, data, len);
861 if (error) {
862 m_freem(info->mreq);
863 info->mreq = NULL;
864 }
865 }
866 return (error);
867}
868
869/*
870 * Caller is expected to abort if a negative value is returned. This
871 * function sets *errorp. Caller should not modify the error code.
872 */
873int
874nfsm_reply(nfsm_info_t info,
875 struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
876 int siz, int *errorp)
877{
878 nfsd->nd_repstat = *errorp;
879 if (*errorp && !(nfsd->nd_flag & ND_NFSV3))
880 siz = 0;
881 nfs_rephead(siz, nfsd, slp, *errorp, &info->mreq,
882 &info->mb, &info->bpos);
883 if (info->mrep != NULL) {
884 m_freem(info->mrep);
885 info->mrep = NULL;
886 }
887 if (*errorp && (!(nfsd->nd_flag & ND_NFSV3) || *errorp == EBADRPC)) {
888 *errorp = 0;
889 return(-1);
890 }
891 return(0);
892}
893
894void
895nfsm_writereply(nfsm_info_t info,
896 struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
897 int error, int siz)
898{
899 nfsd->nd_repstat = error;
900 if (error && !(info->v3))
901 siz = 0;
902 nfs_rephead(siz, nfsd, slp, error, &info->mreq, &info->mb, &info->bpos);
903}
904
905/*
906 * Caller is expected to abort if a non-zero error is returned.
907 */
908int
909nfsm_adv(nfsm_info_t info, int len)
910{
911 int error;
912 int n;
913
914 n = mtod(info->md, caddr_t) + info->md->m_len - info->dpos;
915 if (n >= len) {
916 info->dpos += len;
917 error = 0;
918 } else if ((error = nfs_adv(&info->md, &info->dpos, len, n)) != 0) {
919 m_freem(info->mrep);
920 info->mrep = NULL;
921 }
922 return (error);
923}
924
925/*
926 * Caller is expected to abort if a negative length is returned, but also
927 * call nfsm_reply(0) if -2 is returned.
928 *
929 * This function sets *errorp. Caller should not modify the error code.
930 */
931int
932nfsm_srvmtofh(nfsm_info_t info, struct nfsrv_descript *nfsd,
933 fhandle_t *fhp, int *errorp)
934{
935 u_int32_t *tl;
936 int fhlen;
937
938 if (nfsd->nd_flag & ND_NFSV3) {
939 tl = nfsm_dissect(info, NFSX_UNSIGNED);
940 if (tl == NULL) {
941 *errorp = EBADRPC;
942 return(-1);
943 }
944 fhlen = fxdr_unsigned(int, *tl);
945 if (fhlen != 0 && fhlen != NFSX_V3FH) {
946 *errorp = EBADRPC;
947 return(-2);
948 }
949 } else {
950 fhlen = NFSX_V2FH;
951 }
952 if (fhlen != 0) {
953 tl = nfsm_dissect(info, fhlen);
954 if (tl == NULL) {
955 *errorp = EBADRPC;
956 return(-1);
957 }
958 bcopy(tl, fhp, fhlen);
959 } else {
960 bzero(fhp, NFSX_V3FH);
961 }
962 return(0);
963}
964
965void *
8bfa5617
MD
966_nfsm_clget(nfsm_info_t info, struct mbuf **mp1, struct mbuf **mp2,
967 char **bp, char **be)
42edf14f 968{
8bfa5617
MD
969 if (*bp >= *be) {
970 if (*mp1 == info->mb)
971 (*mp1)->m_len += *bp - info->bpos;
972 *mp1 = m_getcl(MB_WAIT, MT_DATA, 0);
973 (*mp1)->m_len = MCLBYTES;
974 (*mp2)->m_next = *mp1;
975 *mp2 = *mp1;
976 *bp = mtod(*mp1, caddr_t);
977 *be = *bp + (*mp1)->m_len;
978 }
979 return(*bp);
42edf14f
MD
980}
981
982int
983nfsm_srvsattr(nfsm_info_t info, struct vattr *vap)
984{
985 u_int32_t *tl;
986 int error = 0;
987
988 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
989 if (*tl == nfs_true) {
990 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
991 vap->va_mode = nfstov_mode(*tl);
992 }
993 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
994 if (*tl == nfs_true) {
995 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
996 vap->va_uid = fxdr_unsigned(uid_t, *tl);
997 }
998 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
999 if (*tl == nfs_true) {
1000 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
1001 vap->va_gid = fxdr_unsigned(gid_t, *tl);
1002 }
1003 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
1004 if (*tl == nfs_true) {
1005 NULLOUT(tl = nfsm_dissect(info, 2 * NFSX_UNSIGNED));
1006 vap->va_size = fxdr_hyper(tl);
1007 }
1008 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
1009 switch (fxdr_unsigned(int, *tl)) {
1010 case NFSV3SATTRTIME_TOCLIENT:
1011 NULLOUT(tl = nfsm_dissect(info, 2 * NFSX_UNSIGNED));
1012 fxdr_nfsv3time(tl, &vap->va_atime);
1013 break;
1014 case NFSV3SATTRTIME_TOSERVER:
1015 getnanotime(&vap->va_atime);
1016 break;
1017 };
1018 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
1019 switch (fxdr_unsigned(int, *tl)) {
1020 case NFSV3SATTRTIME_TOCLIENT:
1021 NULLOUT(tl = nfsm_dissect(info, 2 * NFSX_UNSIGNED));
1022 fxdr_nfsv3time(tl, &vap->va_mtime);
1023 break;
1024 case NFSV3SATTRTIME_TOSERVER:
1025 getnanotime(&vap->va_mtime);
1026 break;
1027 }
1028nfsmout:
1029 return (error);
e97453f3
MD
1030}
1031
1032/*
1033 * copies mbuf chain to the uio scatter/gather list
1034 */
1035int
1036nfsm_mbuftouio(struct mbuf **mrep, struct uio *uiop, int siz, caddr_t *dpos)
1037{
1038 char *mbufcp, *uiocp;
1039 int xfer, left, len;
1040 struct mbuf *mp;
1041 long uiosiz, rem;
1042 int error = 0;
1043
1044 mp = *mrep;
1045 mbufcp = *dpos;
1046 len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
1047 rem = nfsm_rndup(siz)-siz;
1048 while (siz > 0) {
1049 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
1050 return (EFBIG);
1051 left = uiop->uio_iov->iov_len;
1052 uiocp = uiop->uio_iov->iov_base;
1053 if (left > siz)
1054 left = siz;
1055 uiosiz = left;
1056 while (left > 0) {
1057 while (len == 0) {
1058 mp = mp->m_next;
1059 if (mp == NULL)
1060 return (EBADRPC);
1061 mbufcp = mtod(mp, caddr_t);
1062 len = mp->m_len;
1063 }
1064 xfer = (left > len) ? len : left;
1065#ifdef notdef
1066 /* Not Yet.. */
1067 if (uiop->uio_iov->iov_op != NULL)
1068 (*(uiop->uio_iov->iov_op))
1069 (mbufcp, uiocp, xfer);
1070 else
1071#endif
1072 if (uiop->uio_segflg == UIO_SYSSPACE)
1073 bcopy(mbufcp, uiocp, xfer);
1074 else
1075 copyout(mbufcp, uiocp, xfer);
1076 left -= xfer;
1077 len -= xfer;
1078 mbufcp += xfer;
1079 uiocp += xfer;
1080 uiop->uio_offset += xfer;
1081 uiop->uio_resid -= xfer;
1082 }
1083 if (uiop->uio_iov->iov_len <= siz) {
1084 uiop->uio_iovcnt--;
1085 uiop->uio_iov++;
1086 } else {
1087 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + uiosiz;
1088 uiop->uio_iov->iov_len -= uiosiz;
1089 }
1090 siz -= uiosiz;
1091 }
1092 *dpos = mbufcp;
1093 *mrep = mp;
1094 if (rem > 0) {
1095 if (len < rem)
1096 error = nfs_adv(mrep, dpos, rem, len);
1097 else
1098 *dpos += rem;
1099 }
1100 return (error);
1101}
1102
1103/*
edb90c22
MD
1104 * copies mbuf chain to the bio buffer
1105 */
1106int
1107nfsm_mbuftobio(struct mbuf **mrep, struct bio *bio, int size, caddr_t *dpos)
1108{
1109 struct buf *bp = bio->bio_buf;
1110 char *mbufcp;
1111 char *bio_cp;
1112 int xfer, len;
1113 struct mbuf *mp;
1114 long rem;
1115 int error = 0;
1116 int bio_left;
1117
1118 mp = *mrep;
1119 mbufcp = *dpos;
1120 len = mtod(mp, caddr_t) + mp->m_len - mbufcp;
1121 rem = nfsm_rndup(size) - size;
1122
1123 bio_left = bp->b_bcount;
1124 bio_cp = bp->b_data;
1125
1126 while (size > 0) {
1127 while (len == 0) {
1128 mp = mp->m_next;
1129 if (mp == NULL)
1130 return (EBADRPC);
1131 mbufcp = mtod(mp, caddr_t);
1132 len = mp->m_len;
1133 }
1134 if ((xfer = len) > size)
1135 xfer = size;
1136 if (bio_left) {
1137 if (xfer > bio_left)
1138 xfer = bio_left;
1139 bcopy(mbufcp, bio_cp, xfer);
1140 } else {
1141 /*
1142 * Not enough buffer space in the bio.
1143 */
1144 return(EFBIG);
1145 }
1146 size -= xfer;
1147 bio_left -= xfer;
1148 bio_cp += xfer;
1149 len -= xfer;
1150 mbufcp += xfer;
1151 }
1152 *dpos = mbufcp;
1153 *mrep = mp;
1154 if (rem > 0) {
1155 if (len < rem)
1156 error = nfs_adv(mrep, dpos, rem, len);
1157 else
1158 *dpos += rem;
1159 }
1160 return (error);
1161}
1162
1163/*
e97453f3
MD
1164 * copies a uio scatter/gather list to an mbuf chain.
1165 * NOTE: can ony handle iovcnt == 1
1166 */
1167int
1168nfsm_uiotombuf(struct uio *uiop, struct mbuf **mq, int siz, caddr_t *bpos)
1169{
1170 char *uiocp;
1171 struct mbuf *mp, *mp2;
1172 int xfer, left, mlen;
1173 int uiosiz, rem;
1174 boolean_t getcluster;
1175 char *cp;
1176
1177#ifdef DIAGNOSTIC
1178 if (uiop->uio_iovcnt != 1)
1179 panic("nfsm_uiotombuf: iovcnt != 1");
1180#endif
1181
1182 if (siz >= MINCLSIZE)
1183 getcluster = TRUE;
1184 else
1185 getcluster = FALSE;
1186 rem = nfsm_rndup(siz) - siz;
1187 mp = mp2 = *mq;
1188 while (siz > 0) {
1189 left = uiop->uio_iov->iov_len;
1190 uiocp = uiop->uio_iov->iov_base;
1191 if (left > siz)
1192 left = siz;
1193 uiosiz = left;
1194 while (left > 0) {
1195 mlen = M_TRAILINGSPACE(mp);
1196 if (mlen == 0) {
1197 if (getcluster)
1198 mp = m_getcl(MB_WAIT, MT_DATA, 0);
1199 else
1200 mp = m_get(MB_WAIT, MT_DATA);
1201 mp->m_len = 0;
1202 mp2->m_next = mp;
1203 mp2 = mp;
1204 mlen = M_TRAILINGSPACE(mp);
1205 }
1206 xfer = (left > mlen) ? mlen : left;
1207#ifdef notdef
1208 /* Not Yet.. */
1209 if (uiop->uio_iov->iov_op != NULL)
1210 (*(uiop->uio_iov->iov_op))
1211 (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
1212 else
1213#endif
1214 if (uiop->uio_segflg == UIO_SYSSPACE)
1215 bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
1216 else
1217 copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
1218 mp->m_len += xfer;
1219 left -= xfer;
1220 uiocp += xfer;
1221 uiop->uio_offset += xfer;
1222 uiop->uio_resid -= xfer;
1223 }
1224 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + uiosiz;
1225 uiop->uio_iov->iov_len -= uiosiz;
1226 siz -= uiosiz;
1227 }
1228 if (rem > 0) {
1229 if (rem > M_TRAILINGSPACE(mp)) {
1230 MGET(mp, MB_WAIT, MT_DATA);
1231 mp->m_len = 0;
1232 mp2->m_next = mp;
1233 }
1234 cp = mtod(mp, caddr_t)+mp->m_len;
1235 for (left = 0; left < rem; left++)
1236 *cp++ = '\0';
1237 mp->m_len += rem;
1238 *bpos = cp;
1239 } else
1240 *bpos = mtod(mp, caddr_t)+mp->m_len;
1241 *mq = mp;
1242 return (0);
1243}
1244
cc7d050e
MD
1245int
1246nfsm_biotombuf(struct bio *bio, struct mbuf **mq, int off,
1247 int siz, caddr_t *bpos)
1248{
1249 struct buf *bp = bio->bio_buf;
1250 struct mbuf *mp, *mp2;
1251 char *bio_cp;
1252 int bio_left;
1253 int xfer, mlen;
1254 int rem;
1255 boolean_t getcluster;
1256 char *cp;
1257
1258 if (siz >= MINCLSIZE)
1259 getcluster = TRUE;
1260 else
1261 getcluster = FALSE;
1262 rem = nfsm_rndup(siz) - siz;
1263 mp = mp2 = *mq;
1264
1265 bio_cp = bp->b_data + off;
1266 bio_left = siz;
1267
1268 while (bio_left) {
1269 mlen = M_TRAILINGSPACE(mp);
1270 if (mlen == 0) {
1271 if (getcluster)
1272 mp = m_getcl(MB_WAIT, MT_DATA, 0);
1273 else
1274 mp = m_get(MB_WAIT, MT_DATA);
1275 mp->m_len = 0;
1276 mp2->m_next = mp;
1277 mp2 = mp;
1278 mlen = M_TRAILINGSPACE(mp);
1279 }
1280 xfer = (bio_left < mlen) ? bio_left : mlen;
1281 bcopy(bio_cp, mtod(mp, caddr_t) + mp->m_len, xfer);
1282 mp->m_len += xfer;
1283 bio_left -= xfer;
1284 bio_cp += xfer;
1285 }
1286 if (rem > 0) {
1287 if (rem > M_TRAILINGSPACE(mp)) {
1288 MGET(mp, MB_WAIT, MT_DATA);
1289 mp->m_len = 0;
1290 mp2->m_next = mp;
1291 }
1292 cp = mtod(mp, caddr_t) + mp->m_len;
1293 for (mlen = 0; mlen < rem; mlen++)
1294 *cp++ = '\0';
1295 mp->m_len += rem;
1296 *bpos = cp;
1297 } else {
1298 *bpos = mtod(mp, caddr_t) + mp->m_len;
1299 }
1300 *mq = mp;
1301 return(0);
1302}
1303
e97453f3
MD
1304/*
1305 * Help break down an mbuf chain by setting the first siz bytes contiguous
1306 * pointed to by returned val.
1307 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
1308 * cases. (The macros use the vars. dpos and dpos2)
1309 */
1310int
1311nfsm_disct(struct mbuf **mdp, caddr_t *dposp, int siz, int left, caddr_t *cp2)
1312{
1313 struct mbuf *mp, *mp2;
1314 int siz2, xfer;
1315 caddr_t p;
1316
1317 mp = *mdp;
1318 while (left == 0) {
1319 *mdp = mp = mp->m_next;
1320 if (mp == NULL)
1321 return (EBADRPC);
1322 left = mp->m_len;
1323 *dposp = mtod(mp, caddr_t);
1324 }
1325 if (left >= siz) {
1326 *cp2 = *dposp;
1327 *dposp += siz;
1328 } else if (mp->m_next == NULL) {
1329 return (EBADRPC);
1330 } else if (siz > MHLEN) {
1331 panic("nfs S too big");
1332 } else {
1333 MGET(mp2, MB_WAIT, MT_DATA);
1334 mp2->m_next = mp->m_next;
1335 mp->m_next = mp2;
1336 mp->m_len -= left;
1337 mp = mp2;
1338 *cp2 = p = mtod(mp, caddr_t);
1339 bcopy(*dposp, p, left); /* Copy what was left */
1340 siz2 = siz-left;
1341 p += left;
1342 mp2 = mp->m_next;
1343 /* Loop around copying up the siz2 bytes */
1344 while (siz2 > 0) {
1345 if (mp2 == NULL)
1346 return (EBADRPC);
1347 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
1348 if (xfer > 0) {
1349 bcopy(mtod(mp2, caddr_t), p, xfer);
e97453f3 1350 mp2->m_len -= xfer;
42edf14f 1351 mp2->m_data += xfer;
e97453f3
MD
1352 p += xfer;
1353 siz2 -= xfer;
1354 }
1355 if (siz2 > 0)
1356 mp2 = mp2->m_next;
1357 }
1358 mp->m_len = siz;
1359 *mdp = mp2;
1360 *dposp = mtod(mp2, caddr_t);
1361 }
1362 return (0);
1363}
1364
1365/*
1366 * Advance the position in the mbuf chain.
1367 */
1368int
1369nfs_adv(struct mbuf **mdp, caddr_t *dposp, int offs, int left)
1370{
1371 struct mbuf *m;
1372 int s;
1373
1374 m = *mdp;
1375 s = left;
1376 while (s < offs) {
1377 offs -= s;
1378 m = m->m_next;
1379 if (m == NULL)
1380 return (EBADRPC);
1381 s = m->m_len;
1382 }
1383 *mdp = m;
1384 *dposp = mtod(m, caddr_t)+offs;
1385 return (0);
1386}
1387
1388/*
1389 * Copy a string into mbufs for the hard cases...
1390 */
1391int
1392nfsm_strtmbuf(struct mbuf **mb, char **bpos, const char *cp, long siz)
1393{
1394 struct mbuf *m1 = NULL, *m2;
1395 long left, xfer, len, tlen;
1396 u_int32_t *tl;
1397 int putsize;
1398
1399 putsize = 1;
1400 m2 = *mb;
1401 left = M_TRAILINGSPACE(m2);
1402 if (left > 0) {
1403 tl = ((u_int32_t *)(*bpos));
1404 *tl++ = txdr_unsigned(siz);
1405 putsize = 0;
1406 left -= NFSX_UNSIGNED;
1407 m2->m_len += NFSX_UNSIGNED;
1408 if (left > 0) {
1409 bcopy(cp, (caddr_t) tl, left);
1410 siz -= left;
1411 cp += left;
1412 m2->m_len += left;
1413 left = 0;
1414 }
1415 }
1416 /* Loop around adding mbufs */
1417 while (siz > 0) {
1418 int msize;
1419
1420 m1 = m_getl(siz, MB_WAIT, MT_DATA, 0, &msize);
1421 m1->m_len = msize;
1422 m2->m_next = m1;
1423 m2 = m1;
1424 tl = mtod(m1, u_int32_t *);
1425 tlen = 0;
1426 if (putsize) {
1427 *tl++ = txdr_unsigned(siz);
1428 m1->m_len -= NFSX_UNSIGNED;
1429 tlen = NFSX_UNSIGNED;
1430 putsize = 0;
1431 }
1432 if (siz < m1->m_len) {
1433 len = nfsm_rndup(siz);
1434 xfer = siz;
1435 if (xfer < len)
1436 *(tl+(xfer>>2)) = 0;
1437 } else {
1438 xfer = len = m1->m_len;
1439 }
1440 bcopy(cp, (caddr_t) tl, xfer);
1441 m1->m_len = len+tlen;
1442 siz -= xfer;
1443 cp += xfer;
1444 }
1445 *mb = m1;
1446 *bpos = mtod(m1, caddr_t)+m1->m_len;
1447 return (0);
1448}
1449
1450/*
1451 * A fiddled version of m_adj() that ensures null fill to a long
1452 * boundary and only trims off the back end
1453 */
1454void
1455nfsm_adj(struct mbuf *mp, int len, int nul)
1456{
1457 struct mbuf *m;
1458 int count, i;
1459 char *cp;
1460
1461 /*
1462 * Trim from tail. Scan the mbuf chain,
1463 * calculating its length and finding the last mbuf.
1464 * If the adjustment only affects this mbuf, then just
1465 * adjust and return. Otherwise, rescan and truncate
1466 * after the remaining size.
1467 */
1468 count = 0;
1469 m = mp;
1470 for (;;) {
1471 count += m->m_len;
1472 if (m->m_next == NULL)
1473 break;
1474 m = m->m_next;
1475 }
1476 if (m->m_len > len) {
1477 m->m_len -= len;
1478 if (nul > 0) {
1479 cp = mtod(m, caddr_t)+m->m_len-nul;
1480 for (i = 0; i < nul; i++)
1481 *cp++ = '\0';
1482 }
1483 return;
1484 }
1485 count -= len;
1486 if (count < 0)
1487 count = 0;
1488 /*
1489 * Correct length for chain is "count".
1490 * Find the mbuf with last data, adjust its length,
1491 * and toss data from remaining mbufs on chain.
1492 */
1493 for (m = mp; m; m = m->m_next) {
1494 if (m->m_len >= count) {
1495 m->m_len = count;
1496 if (nul > 0) {
1497 cp = mtod(m, caddr_t)+m->m_len-nul;
1498 for (i = 0; i < nul; i++)
1499 *cp++ = '\0';
1500 }
1501 break;
1502 }
1503 count -= m->m_len;
1504 }
1505 for (m = m->m_next;m;m = m->m_next)
1506 m->m_len = 0;
1507}
1508
1509/*
1510 * Make these functions instead of macros, so that the kernel text size
1511 * doesn't get too big...
1512 */
1513void
42edf14f
MD
1514nfsm_srvwcc_data(nfsm_info_t info, struct nfsrv_descript *nfsd,
1515 int before_ret, struct vattr *before_vap,
1516 int after_ret, struct vattr *after_vap)
e97453f3 1517{
e97453f3
MD
1518 u_int32_t *tl;
1519
1520 /*
1521 * before_ret is 0 if before_vap is valid, non-zero if it isn't.
1522 */
1523 if (before_ret) {
42edf14f 1524 tl = nfsm_build(info, NFSX_UNSIGNED);
e97453f3
MD
1525 *tl = nfs_false;
1526 } else {
42edf14f 1527 tl = nfsm_build(info, 7 * NFSX_UNSIGNED);
e97453f3
MD
1528 *tl++ = nfs_true;
1529 txdr_hyper(before_vap->va_size, tl);
1530 tl += 2;
1531 txdr_nfsv3time(&(before_vap->va_mtime), tl);
1532 tl += 2;
1533 txdr_nfsv3time(&(before_vap->va_ctime), tl);
1534 }
42edf14f 1535 nfsm_srvpostop_attr(info, nfsd, after_ret, after_vap);
e97453f3
MD
1536}
1537
1538void
42edf14f
MD
1539nfsm_srvpostop_attr(nfsm_info_t info, struct nfsrv_descript *nfsd,
1540 int after_ret, struct vattr *after_vap)
e97453f3 1541{
e97453f3 1542 struct nfs_fattr *fp;
42edf14f 1543 u_int32_t *tl;
e97453f3
MD
1544
1545 if (after_ret) {
42edf14f 1546 tl = nfsm_build(info, NFSX_UNSIGNED);
e97453f3
MD
1547 *tl = nfs_false;
1548 } else {
42edf14f 1549 tl = nfsm_build(info, NFSX_UNSIGNED + NFSX_V3FATTR);
e97453f3
MD
1550 *tl++ = nfs_true;
1551 fp = (struct nfs_fattr *)tl;
1552 nfsm_srvfattr(nfsd, after_vap, fp);
1553 }
e97453f3
MD
1554}
1555
1556void
1557nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
1558 struct nfs_fattr *fp)
1559{
1560 /*
1561 * NFS seems to truncate nlink to 16 bits, don't let it overflow.
1562 */
1563 if (vap->va_nlink > 65535)
1564 fp->fa_nlink = 65535;
1565 else
1566 fp->fa_nlink = txdr_unsigned(vap->va_nlink);
1567 fp->fa_uid = txdr_unsigned(vap->va_uid);
1568 fp->fa_gid = txdr_unsigned(vap->va_gid);
1569 if (nfsd->nd_flag & ND_NFSV3) {
1570 fp->fa_type = vtonfsv3_type(vap->va_type);
1571 fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1572 txdr_hyper(vap->va_size, &fp->fa3_size);
1573 txdr_hyper(vap->va_bytes, &fp->fa3_used);
1574 fp->fa3_rdev.specdata1 = txdr_unsigned(vap->va_rmajor);
1575 fp->fa3_rdev.specdata2 = txdr_unsigned(vap->va_rminor);
1576 fp->fa3_fsid.nfsuquad[0] = 0;
1577 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1578 txdr_hyper(vap->va_fileid, &fp->fa3_fileid);
1579 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1580 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1581 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1582 } else {
1583 fp->fa_type = vtonfsv2_type(vap->va_type);
1584 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1585 fp->fa2_size = txdr_unsigned(vap->va_size);
1586 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1587 if (vap->va_type == VFIFO)
1588 fp->fa2_rdev = 0xffffffff;
1589 else
1590 fp->fa2_rdev = txdr_unsigned(makeudev(vap->va_rmajor, vap->va_rminor));
1591 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1592 fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1593 fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1594 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1595 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1596 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1597 }
1598}