2 * Copyright (c) 2009 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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
35 * Copyright (c) 1989, 1993
36 * The Regents of the University of California. All rights reserved.
38 * This code is derived from software contributed to Berkeley by
39 * Rick Macklem at The University of Guelph.
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
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.
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
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.
75 #include <sys/param.h>
76 #include <sys/systm.h>
77 #include <sys/kernel.h>
80 #include <sys/mount.h>
81 #include <sys/vnode.h>
82 #include <sys/nlookup.h>
83 #include <sys/namei.h>
85 #include <sys/socket.h>
87 #include <sys/malloc.h>
88 #include <sys/sysent.h>
89 #include <sys/syscall.h>
91 #include <sys/objcache.h>
94 #include <vm/vm_object.h>
95 #include <vm/vm_extern.h>
96 #include <vm/vm_zone.h>
101 #include "nfsproto.h"
103 #include "nfsmount.h"
105 #include "xdr_subs.h"
106 #include "nfsm_subs.h"
109 #include <netinet/in.h>
111 static u_int32_t nfs_xid = 0;
114 * Create the header for an rpc request packet
115 * The hsiz is the size of the rest of the nfs request header.
116 * (just used to decide if a cluster is a good idea)
119 nfsm_reqh(struct vnode *vp, u_long procid, int hsiz, caddr_t *bposp)
124 mb = m_getl(hsiz, MB_WAIT, MT_DATA, 0, NULL);
126 bpos = mtod(mb, caddr_t);
128 /* Finally, return values */
134 * Build the RPC header and fill in the authorization info.
135 * The authorization string argument is only used when the credentials
136 * come from outside of the kernel.
137 * Returns the head of the mbuf list.
140 nfsm_rpchead(struct ucred *cr, int nmflag, int procid, int auth_type,
141 int auth_len, char *auth_str, int verf_len, char *verf_str,
142 struct mbuf *mrest, int mrest_len, struct mbuf **mbp,
149 struct mbuf *mreq, *mb2;
150 int siz, grpsiz, authsiz, dsiz;
152 authsiz = nfsm_rndup(auth_len);
153 dsiz = authsiz + 10 * NFSX_UNSIGNED;
154 mb = m_getl(dsiz, MB_WAIT, MT_DATA, M_PKTHDR, NULL);
155 if (dsiz < MINCLSIZE) {
159 MH_ALIGN(mb, 8 * NFSX_UNSIGNED);
161 mb->m_len = mb->m_pkthdr.len = 0;
163 bpos = mtod(mb, caddr_t);
166 * First the RPC header.
168 nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
170 /* Get a pretty random xid to start with */
174 * Skip zero xid if it should ever happen.
179 *tl++ = *xidp = txdr_unsigned(nfs_xid);
182 *tl++ = txdr_unsigned(NFS_PROG);
183 if (nmflag & NFSMNT_NFSV3)
184 *tl++ = txdr_unsigned(NFS_VER3);
186 *tl++ = txdr_unsigned(NFS_VER2);
187 if (nmflag & NFSMNT_NFSV3)
188 *tl++ = txdr_unsigned(procid);
190 *tl++ = txdr_unsigned(nfsv2_procid[procid]);
193 * And then the authorization cred.
195 *tl++ = txdr_unsigned(auth_type);
196 *tl = txdr_unsigned(authsiz);
199 nfsm_build(tl, u_int32_t *, auth_len);
200 *tl++ = 0; /* stamp ?? */
201 *tl++ = 0; /* NULL hostname */
202 *tl++ = txdr_unsigned(cr->cr_uid);
203 *tl++ = txdr_unsigned(cr->cr_groups[0]);
204 grpsiz = (auth_len >> 2) - 5;
205 *tl++ = txdr_unsigned(grpsiz);
206 for (i = 1; i <= grpsiz; i++)
207 *tl++ = txdr_unsigned(cr->cr_groups[i]);
212 if (M_TRAILINGSPACE(mb) == 0) {
213 mb2 = m_getl(siz, MB_WAIT, MT_DATA, 0, NULL);
217 bpos = mtod(mb, caddr_t);
219 i = min(siz, M_TRAILINGSPACE(mb));
220 bcopy(auth_str, bpos, i);
226 if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
227 for (i = 0; i < siz; i++)
235 * And the verifier...
237 nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
239 *tl++ = txdr_unsigned(RPCAUTH_KERB4);
240 *tl = txdr_unsigned(verf_len);
243 if (M_TRAILINGSPACE(mb) == 0) {
244 mb2 = m_getl(siz, MB_WAIT, MT_DATA, 0, NULL);
248 bpos = mtod(mb, caddr_t);
250 i = min(siz, M_TRAILINGSPACE(mb));
251 bcopy(verf_str, bpos, i);
257 if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
258 for (i = 0; i < siz; i++)
263 *tl++ = txdr_unsigned(RPCAUTH_NULL);
267 mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
268 mreq->m_pkthdr.rcvif = NULL;
274 * copies mbuf chain to the uio scatter/gather list
277 nfsm_mbuftouio(struct mbuf **mrep, struct uio *uiop, int siz, caddr_t *dpos)
279 char *mbufcp, *uiocp;
287 len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
288 rem = nfsm_rndup(siz)-siz;
290 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
292 left = uiop->uio_iov->iov_len;
293 uiocp = uiop->uio_iov->iov_base;
302 mbufcp = mtod(mp, caddr_t);
305 xfer = (left > len) ? len : left;
308 if (uiop->uio_iov->iov_op != NULL)
309 (*(uiop->uio_iov->iov_op))
310 (mbufcp, uiocp, xfer);
313 if (uiop->uio_segflg == UIO_SYSSPACE)
314 bcopy(mbufcp, uiocp, xfer);
316 copyout(mbufcp, uiocp, xfer);
321 uiop->uio_offset += xfer;
322 uiop->uio_resid -= xfer;
324 if (uiop->uio_iov->iov_len <= siz) {
328 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + uiosiz;
329 uiop->uio_iov->iov_len -= uiosiz;
337 error = nfs_adv(mrep, dpos, rem, len);
345 * copies a uio scatter/gather list to an mbuf chain.
346 * NOTE: can ony handle iovcnt == 1
349 nfsm_uiotombuf(struct uio *uiop, struct mbuf **mq, int siz, caddr_t *bpos)
352 struct mbuf *mp, *mp2;
353 int xfer, left, mlen;
355 boolean_t getcluster;
359 if (uiop->uio_iovcnt != 1)
360 panic("nfsm_uiotombuf: iovcnt != 1");
363 if (siz >= MINCLSIZE)
367 rem = nfsm_rndup(siz) - siz;
370 left = uiop->uio_iov->iov_len;
371 uiocp = uiop->uio_iov->iov_base;
376 mlen = M_TRAILINGSPACE(mp);
379 mp = m_getcl(MB_WAIT, MT_DATA, 0);
381 mp = m_get(MB_WAIT, MT_DATA);
385 mlen = M_TRAILINGSPACE(mp);
387 xfer = (left > mlen) ? mlen : left;
390 if (uiop->uio_iov->iov_op != NULL)
391 (*(uiop->uio_iov->iov_op))
392 (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
395 if (uiop->uio_segflg == UIO_SYSSPACE)
396 bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
398 copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
402 uiop->uio_offset += xfer;
403 uiop->uio_resid -= xfer;
405 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + uiosiz;
406 uiop->uio_iov->iov_len -= uiosiz;
410 if (rem > M_TRAILINGSPACE(mp)) {
411 MGET(mp, MB_WAIT, MT_DATA);
415 cp = mtod(mp, caddr_t)+mp->m_len;
416 for (left = 0; left < rem; left++)
421 *bpos = mtod(mp, caddr_t)+mp->m_len;
427 * Help break down an mbuf chain by setting the first siz bytes contiguous
428 * pointed to by returned val.
429 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
430 * cases. (The macros use the vars. dpos and dpos2)
433 nfsm_disct(struct mbuf **mdp, caddr_t *dposp, int siz, int left, caddr_t *cp2)
435 struct mbuf *mp, *mp2;
441 *mdp = mp = mp->m_next;
445 *dposp = mtod(mp, caddr_t);
450 } else if (mp->m_next == NULL) {
452 } else if (siz > MHLEN) {
453 panic("nfs S too big");
455 MGET(mp2, MB_WAIT, MT_DATA);
456 mp2->m_next = mp->m_next;
460 *cp2 = p = mtod(mp, caddr_t);
461 bcopy(*dposp, p, left); /* Copy what was left */
465 /* Loop around copying up the siz2 bytes */
469 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
471 bcopy(mtod(mp2, caddr_t), p, xfer);
482 *dposp = mtod(mp2, caddr_t);
488 * Advance the position in the mbuf chain.
491 nfs_adv(struct mbuf **mdp, caddr_t *dposp, int offs, int left)
506 *dposp = mtod(m, caddr_t)+offs;
511 * Copy a string into mbufs for the hard cases...
514 nfsm_strtmbuf(struct mbuf **mb, char **bpos, const char *cp, long siz)
516 struct mbuf *m1 = NULL, *m2;
517 long left, xfer, len, tlen;
523 left = M_TRAILINGSPACE(m2);
525 tl = ((u_int32_t *)(*bpos));
526 *tl++ = txdr_unsigned(siz);
528 left -= NFSX_UNSIGNED;
529 m2->m_len += NFSX_UNSIGNED;
531 bcopy(cp, (caddr_t) tl, left);
538 /* Loop around adding mbufs */
542 m1 = m_getl(siz, MB_WAIT, MT_DATA, 0, &msize);
546 tl = mtod(m1, u_int32_t *);
549 *tl++ = txdr_unsigned(siz);
550 m1->m_len -= NFSX_UNSIGNED;
551 tlen = NFSX_UNSIGNED;
554 if (siz < m1->m_len) {
555 len = nfsm_rndup(siz);
560 xfer = len = m1->m_len;
562 bcopy(cp, (caddr_t) tl, xfer);
563 m1->m_len = len+tlen;
568 *bpos = mtod(m1, caddr_t)+m1->m_len;
573 * A fiddled version of m_adj() that ensures null fill to a long
574 * boundary and only trims off the back end
577 nfsm_adj(struct mbuf *mp, int len, int nul)
584 * Trim from tail. Scan the mbuf chain,
585 * calculating its length and finding the last mbuf.
586 * If the adjustment only affects this mbuf, then just
587 * adjust and return. Otherwise, rescan and truncate
588 * after the remaining size.
594 if (m->m_next == NULL)
598 if (m->m_len > len) {
601 cp = mtod(m, caddr_t)+m->m_len-nul;
602 for (i = 0; i < nul; i++)
611 * Correct length for chain is "count".
612 * Find the mbuf with last data, adjust its length,
613 * and toss data from remaining mbufs on chain.
615 for (m = mp; m; m = m->m_next) {
616 if (m->m_len >= count) {
619 cp = mtod(m, caddr_t)+m->m_len-nul;
620 for (i = 0; i < nul; i++)
627 for (m = m->m_next;m;m = m->m_next)
632 * Make these functions instead of macros, so that the kernel text size
633 * doesn't get too big...
636 nfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret,
637 struct vattr *before_vap, int after_ret, struct vattr *after_vap,
638 struct mbuf **mbp, char **bposp)
640 struct mbuf *mb = *mbp, *mb2;
645 * before_ret is 0 if before_vap is valid, non-zero if it isn't.
648 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
651 nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
653 txdr_hyper(before_vap->va_size, tl);
655 txdr_nfsv3time(&(before_vap->va_mtime), tl);
657 txdr_nfsv3time(&(before_vap->va_ctime), tl);
661 nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
665 nfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret,
666 struct vattr *after_vap, struct mbuf **mbp, char **bposp)
668 struct mbuf *mb = *mbp, *mb2;
671 struct nfs_fattr *fp;
674 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
677 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
679 fp = (struct nfs_fattr *)tl;
680 nfsm_srvfattr(nfsd, after_vap, fp);
687 nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
688 struct nfs_fattr *fp)
691 * NFS seems to truncate nlink to 16 bits, don't let it overflow.
693 if (vap->va_nlink > 65535)
694 fp->fa_nlink = 65535;
696 fp->fa_nlink = txdr_unsigned(vap->va_nlink);
697 fp->fa_uid = txdr_unsigned(vap->va_uid);
698 fp->fa_gid = txdr_unsigned(vap->va_gid);
699 if (nfsd->nd_flag & ND_NFSV3) {
700 fp->fa_type = vtonfsv3_type(vap->va_type);
701 fp->fa_mode = vtonfsv3_mode(vap->va_mode);
702 txdr_hyper(vap->va_size, &fp->fa3_size);
703 txdr_hyper(vap->va_bytes, &fp->fa3_used);
704 fp->fa3_rdev.specdata1 = txdr_unsigned(vap->va_rmajor);
705 fp->fa3_rdev.specdata2 = txdr_unsigned(vap->va_rminor);
706 fp->fa3_fsid.nfsuquad[0] = 0;
707 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
708 txdr_hyper(vap->va_fileid, &fp->fa3_fileid);
709 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
710 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
711 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
713 fp->fa_type = vtonfsv2_type(vap->va_type);
714 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
715 fp->fa2_size = txdr_unsigned(vap->va_size);
716 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
717 if (vap->va_type == VFIFO)
718 fp->fa2_rdev = 0xffffffff;
720 fp->fa2_rdev = txdr_unsigned(makeudev(vap->va_rmajor, vap->va_rminor));
721 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
722 fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
723 fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
724 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
725 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
726 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);