1 /* 2 * Copyright (c) 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Rick Macklem at The University of Guelph. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 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 the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * $Id: nfs_syscalls.c,v 1.1 94/10/20 10:57:35 root Exp $ 37 */ 38 39 #include "sys/param.h" 40 #include "sys/stat.h" 41 #include "privilege.h" 42 #include "sys/mount.h" 43 #include "uio.h" 44 #include "sys/errno.h" 45 #include "proc.h" 46 #include "filedesc.h" 47 #include "malloc.h" 48 #include "buf.h" 49 #include "mbuf.h" 50 #include "socketvar.h" 51 #include "domain.h" 52 #include "protosw.h" 53 54 #include "in.h" 55 #include "tcp.h" 56 57 #include "vnode.h" 58 #include "namei.h" 59 #include "nfs_v2.h" 60 #include "nfs.h" 61 #include "nfs_srvcache.h" 62 63 #include "prototypes.h" 64 65 /* Global defs. */ 66 extern u_long nfs_prog, nfs_vers; 67 extern int (*nfsrv_procs[NFS_NPROCS])(); 68 extern struct buf nfs_bqueue; 69 extern int nfs_numasync; 70 extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 71 extern int nfs_tcpnodelay; 72 struct mbuf *nfs_compress(); 73 74 #define TRUE 1 75 #define FALSE 0 76 77 static int nfs_asyncdaemon[NFS_MAXASYNCDAEMON]; 78 static int compressreply[NFS_NPROCS] = { 79 FALSE, 80 TRUE, 81 TRUE, 82 FALSE, 83 TRUE, 84 TRUE, 85 FALSE, 86 FALSE, 87 TRUE, 88 TRUE, 89 TRUE, 90 TRUE, 91 TRUE, 92 TRUE, 93 TRUE, 94 TRUE, 95 TRUE, 96 TRUE, 97 }; 98 /* 99 * NFS server system calls 100 */ 101 102 /* 103 * Nfs server psuedo system call for the nfsd's 104 * Never returns unless it fails or gets killed 105 */ 106 /* ARGSUSED */ 107 nfssvc(p, uap, retval) 108 struct proc *p; 109 register struct args { 110 int s; 111 caddr_t mskval; 112 int msklen; 113 caddr_t mtchval; 114 int mtchlen; 115 } *uap; 116 int *retval; 117 { 118 register struct mbuf *m; 119 register int siz; 120 struct file *fp; 121 struct mbuf *mreq, *mrep, *nam, *md; 122 struct mbuf msk, mtch; 123 struct socket *so; 124 caddr_t dpos; 125 int procid, repstat, error, cacherep, wascomp; 126 u_long retxid; 127 128 /* 129 * Must be super user 130 */ 131 if (error = use_priv(p->p_ucred, PRV_NFS_SVC, p)) 132 return (error); 133 if (error = getsock(p->p_fd, uap->s, &fp)) 134 return (error); 135 so = (struct socket *)fp->f_data; 136 if (sosendallatonce(so)) 137 siz = NFS_MAXPACKET; 138 else 139 siz = NFS_MAXPACKET + sizeof(u_long); 140 if (error = soreserve(so, siz, siz)) 141 goto bad; 142 if (error = sockargs(&nam, uap->mskval, uap->msklen, MT_SONAME)) 143 goto bad; 144 memcpy((caddr_t)&msk, (caddr_t)nam, sizeof (struct mbuf)); 145 msk.m_data = msk.m_dat; 146 m_freem(nam); 147 if (error = sockargs(&nam, uap->mtchval, uap->mtchlen, MT_SONAME)) 148 goto bad; 149 memcpy((caddr_t)&mtch, (caddr_t)nam, sizeof (struct mbuf)); 150 mtch.m_data = mtch.m_dat; 151 m_freem(nam); 152 153 /* Copy the cred so others don't see changes */ 154 p->p_cred = modpcred(p); 155 156 /* 157 * Set protocol specific options { for now TCP only } and 158 * reserve some space. For datagram sockets, this can get called 159 * repeatedly for the same socket, but that isn't harmful. 160 */ 161 if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 162 MGET(m, M_WAIT, MT_SOOPTS); 163 *mtod(m, int *) = 1; 164 m->m_len = sizeof(int); 165 sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m); 166 } 167 if (so->so_proto->pr_domain->dom_family == AF_INET && 168 so->so_proto->pr_protocol == IPPROTO_TCP && 169 nfs_tcpnodelay) { 170 MGET(m, M_WAIT, MT_SOOPTS); 171 *mtod(m, int *) = 1; 172 m->m_len = sizeof(int); 173 sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m); 174 } 175 so->so_rcv.sb_flags &= ~SB_NOINTR; 176 so->so_rcv.sb_timeo = 0; 177 so->so_snd.sb_flags &= ~SB_NOINTR; 178 so->so_snd.sb_timeo = 0; 179 180 /* 181 * Just loop around doin our stuff until SIGKILL 182 */ 183 for (;;) { 184 if (error = nfs_getreq(so, nfs_prog, nfs_vers, NFS_NPROCS-1, 185 &nam, &mrep, &md, &dpos, &retxid, &procid, p->p_ucred, 186 &msk, &mtch, &wascomp)) { 187 if (nam) 188 m_freem(nam); 189 if (error == EPIPE || error == EINTR || 190 error == ERESTART) { 191 error = 0; 192 goto bad; 193 } 194 so->so_error = 0; 195 continue; 196 } 197 198 if (nam) 199 cacherep = nfsrv_getcache(nam, retxid, procid, &mreq); 200 else 201 cacherep = RC_DOIT; 202 switch (cacherep) { 203 case RC_DOIT: 204 if (error = (*(nfsrv_procs[procid]))(mrep, md, dpos, 205 p->p_ucred, retxid, &mreq, &repstat, p)) { 206 nfsstats.srv_errs++; 207 if (nam) { 208 nfsrv_updatecache(nam, retxid, procid, 209 FALSE, repstat, mreq); 210 m_freem(nam); 211 } 212 break; 213 } 214 nfsstats.srvrpccnt[procid]++; 215 if (nam) 216 nfsrv_updatecache(nam, retxid, procid, TRUE, 217 repstat, mreq); 218 mrep = (struct mbuf *)0; 219 case RC_REPLY: 220 m = mreq; 221 siz = 0; 222 while (m) { 223 siz += m->m_len; 224 m = m->m_next; 225 } 226 if (siz <= 0 || siz > NFS_MAXPACKET) { 227 printf("mbuf siz=%d\n",siz); 228 panic("Bad nfs svc reply"); 229 } 230 mreq->m_pkthdr.len = siz; 231 mreq->m_pkthdr.rcvif = (struct ifnet *)0; 232 if (wascomp && compressreply[procid]) { 233 mreq = nfs_compress(mreq); 234 siz = mreq->m_pkthdr.len; 235 } 236 /* 237 * For non-atomic protocols, prepend a Sun RPC 238 * Record Mark. 239 */ 240 if (!sosendallatonce(so)) { 241 M_PREPEND(mreq, sizeof(u_long), M_WAIT); 242 *mtod(mreq, u_long *) = htonl(0x80000000 | siz); 243 } 244 error = nfs_send(so, nam, mreq, (struct nfsreq *)0); 245 if (nam) 246 m_freem(nam); 247 if (mrep) 248 m_freem(mrep); 249 if (error) { 250 if (error == EPIPE || error == EINTR || 251 error == ERESTART) 252 goto bad; 253 so->so_error = 0; 254 } 255 break; 256 case RC_DROPIT: 257 m_freem(mrep); 258 m_freem(nam); 259 break; 260 }; 261 } 262 bad: 263 return (error); 264 } 265 266 /* 267 * Nfs pseudo system call for asynchronous i/o daemons. 268 * These babies just pretend to be disk interrupt service routines 269 * for client nfs. They are mainly here for read ahead/write behind. 270 * Never returns unless it fails or gets killed 271 */ 272 /* ARGSUSED */ 273 async_daemon(p, uap, retval) 274 struct proc *p; 275 struct args *uap; 276 int *retval; 277 { 278 register struct buf *bp, *dp; 279 register int i, myiod; 280 int error; 281 282 /* 283 * Must be super user 284 */ 285 if (error = use_priv(p->p_ucred, PRV_NFS_ASYNC_DAEMON, p)) 286 return (error); 287 /* 288 * Assign my position or return error if too many already running 289 */ 290 myiod = -1; 291 for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 292 if (nfs_asyncdaemon[i] == 0) { 293 nfs_asyncdaemon[i]++; 294 myiod = i; 295 break; 296 } 297 if (myiod == -1) 298 return (EBUSY); 299 nfs_numasync++; 300 dp = &nfs_bqueue; 301 /* 302 * Just loop around doin our stuff until SIGKILL 303 */ 304 for (;;) { 305 while (dp->b_actf == NULL && error == 0) { 306 nfs_iodwant[myiod] = p; 307 error = tsleep((caddr_t)&nfs_iodwant[myiod], 308 PWAIT | PCATCH, "nfsidl", 0); 309 nfs_iodwant[myiod] = (struct proc *)0; 310 } 311 while (dp->b_actf != NULL) { 312 /* Take one off the end of the list */ 313 bp = dp->b_actl; 314 if (bp->b_actl == dp) { 315 dp->b_actf = dp->b_actl = (struct buf *)0; 316 } else { 317 dp->b_actl = bp->b_actl; 318 bp->b_actl->b_actf = dp; 319 } 320 (void) nfs_doio(bp); 321 } 322 if (error) { 323 nfs_asyncdaemon[myiod] = 0; 324 nfs_numasync--; 325 return (error); 326 } 327 } 328 } 329