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 * from: @(#)nfs_syscalls.c 7.26 (Berkeley) 4/16/91 37 * $Id: nfs_syscalls.c,v 1.5 1993/05/22 11:43:03 cgd Exp $ 38 */ 39 40 #include "param.h" 41 #include "systm.h" 42 #include "kernel.h" 43 #include "file.h" 44 #include "stat.h" 45 #include "namei.h" 46 #include "vnode.h" 47 #include "mount.h" 48 #include "proc.h" 49 #include "malloc.h" 50 #include "buf.h" 51 #include "mbuf.h" 52 #include "socket.h" 53 #include "socketvar.h" 54 #include "domain.h" 55 #include "protosw.h" 56 57 #include "../netinet/in.h" 58 #include "../netinet/tcp.h" 59 60 #include "nfsv2.h" 61 #include "nfs.h" 62 #include "nfsrvcache.h" 63 64 /* Global defs. */ 65 extern u_long nfs_prog, nfs_vers; 66 extern int (*nfsrv_procs[NFS_NPROCS])(); 67 extern struct buf nfs_bqueue; 68 extern int nfs_numasync; 69 extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 70 extern int nfs_tcpnodelay; 71 struct mbuf *nfs_compress(); 72 73 #define TRUE 1 74 #define FALSE 0 75 76 static int nfs_asyncdaemon[NFS_MAXASYNCDAEMON]; 77 static int compressreply[NFS_NPROCS] = { 78 FALSE, 79 TRUE, 80 TRUE, 81 FALSE, 82 TRUE, 83 TRUE, 84 FALSE, 85 FALSE, 86 TRUE, 87 TRUE, 88 TRUE, 89 TRUE, 90 TRUE, 91 TRUE, 92 TRUE, 93 TRUE, 94 TRUE, 95 TRUE, 96 }; 97 98 #ifdef NFSCLIENT 99 100 /* 101 * NFS server system calls 102 * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c 103 */ 104 105 /* 106 * Get file handle system call 107 */ 108 /* ARGSUSED */ 109 getfh(p, uap, retval) 110 struct proc *p; 111 register struct args { 112 char *fname; 113 fhandle_t *fhp; 114 } *uap; 115 int *retval; 116 { 117 register struct nameidata *ndp; 118 register struct vnode *vp; 119 fhandle_t fh; 120 int error; 121 struct nameidata nd; 122 123 /* 124 * Must be super user 125 */ 126 if (error = suser(p->p_ucred, &p->p_acflag)) 127 return (error); 128 ndp = &nd; 129 ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 130 ndp->ni_segflg = UIO_USERSPACE; 131 ndp->ni_dirp = uap->fname; 132 if (error = namei(ndp, p)) 133 return (error); 134 vp = ndp->ni_vp; 135 bzero((caddr_t)&fh, sizeof(fh)); 136 fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid; 137 error = VFS_VPTOFH(vp, &fh.fh_fid); 138 vput(vp); 139 if (error) 140 return (error); 141 error = copyout((caddr_t)&fh, (caddr_t)uap->fhp, sizeof (fh)); 142 return (error); 143 } 144 145 #endif /*NFSCLIENT*/ 146 147 #ifdef NFSSERVER 148 149 /* 150 * Nfs server psuedo system call for the nfsd's 151 * Never returns unless it fails or gets killed 152 */ 153 /* ARGSUSED */ 154 nfssvc(p, uap, retval) 155 struct proc *p; 156 register struct args { 157 int s; 158 caddr_t mskval; 159 int msklen; 160 caddr_t mtchval; 161 int mtchlen; 162 } *uap; 163 int *retval; 164 { 165 register struct mbuf *m; 166 register int siz; 167 register struct ucred *cr; 168 struct file *fp; 169 struct mbuf *mreq, *mrep, *nam, *md; 170 struct mbuf msk, mtch; 171 struct socket *so; 172 caddr_t dpos; 173 int procid, repstat, error, cacherep, wascomp; 174 u_long retxid; 175 176 /* 177 * Must be super user 178 */ 179 if (error = suser(p->p_ucred, &p->p_acflag)) 180 return (error); 181 if (error = getsock(p->p_fd, uap->s, &fp)) 182 return (error); 183 so = (struct socket *)fp->f_data; 184 if (sosendallatonce(so)) 185 siz = NFS_MAXPACKET; 186 else 187 siz = NFS_MAXPACKET + sizeof(u_long); 188 if (error = soreserve(so, siz, siz)) 189 goto bad; 190 if (error = sockargs(&nam, uap->mskval, uap->msklen, MT_SONAME)) 191 goto bad; 192 bcopy((caddr_t)nam, (caddr_t)&msk, sizeof (struct mbuf)); 193 msk.m_data = msk.m_dat; 194 m_freem(nam); 195 if (error = sockargs(&nam, uap->mtchval, uap->mtchlen, MT_SONAME)) 196 goto bad; 197 bcopy((caddr_t)nam, (caddr_t)&mtch, sizeof (struct mbuf)); 198 mtch.m_data = mtch.m_dat; 199 m_freem(nam); 200 201 /* Copy the cred so others don't see changes */ 202 cr = p->p_ucred = crcopy(p->p_ucred); 203 204 /* 205 * Set protocol specific options { for now TCP only } and 206 * reserve some space. For datagram sockets, this can get called 207 * repeatedly for the same socket, but that isn't harmful. 208 */ 209 if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 210 MGET(m, M_WAIT, MT_SOOPTS); 211 *mtod(m, int *) = 1; 212 m->m_len = sizeof(int); 213 sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m); 214 } 215 if (so->so_proto->pr_domain->dom_family == AF_INET && 216 so->so_proto->pr_protocol == IPPROTO_TCP && 217 nfs_tcpnodelay) { 218 MGET(m, M_WAIT, MT_SOOPTS); 219 *mtod(m, int *) = 1; 220 m->m_len = sizeof(int); 221 sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m); 222 } 223 so->so_rcv.sb_flags &= ~SB_NOINTR; 224 so->so_rcv.sb_timeo = 0; 225 so->so_snd.sb_flags &= ~SB_NOINTR; 226 so->so_snd.sb_timeo = 0; 227 228 /* 229 * Just loop around doin our stuff until SIGKILL 230 */ 231 for (;;) { 232 if (error = nfs_getreq(so, nfs_prog, nfs_vers, NFS_NPROCS-1, 233 &nam, &mrep, &md, &dpos, &retxid, &procid, cr, 234 /* 08 Sep 92*/ &msk, &mtch, &wascomp, &repstat)) { 235 if (nam) 236 m_freem(nam); 237 if (error == EPIPE || error == EINTR || 238 error == ERESTART) { 239 error = 0; 240 goto bad; 241 } 242 so->so_error = 0; 243 continue; 244 } 245 246 if (nam) 247 cacherep = nfsrv_getcache(nam, retxid, procid, &mreq); 248 else 249 cacherep = RC_DOIT; 250 switch (cacherep) { 251 case RC_DOIT: 252 if (error = (*(nfsrv_procs[procid]))(mrep, md, dpos, 253 cr, retxid, &mreq, &repstat, p)) { 254 nfsstats.srv_errs++; 255 if (nam) { 256 nfsrv_updatecache(nam, retxid, procid, 257 FALSE, repstat, mreq); 258 m_freem(nam); 259 } 260 break; 261 } 262 nfsstats.srvrpccnt[procid]++; 263 if (nam) 264 nfsrv_updatecache(nam, retxid, procid, TRUE, 265 repstat, mreq); 266 mrep = (struct mbuf *)0; 267 case RC_REPLY: 268 m = mreq; 269 siz = 0; 270 while (m) { 271 siz += m->m_len; 272 m = m->m_next; 273 } 274 if (siz <= 0 || siz > NFS_MAXPACKET) { 275 printf("mbuf siz=%d\n",siz); 276 panic("Bad nfs svc reply"); 277 } 278 mreq->m_pkthdr.len = siz; 279 mreq->m_pkthdr.rcvif = (struct ifnet *)0; 280 if (wascomp && compressreply[procid]) { 281 mreq = nfs_compress(mreq); 282 siz = mreq->m_pkthdr.len; 283 } 284 /* 285 * For non-atomic protocols, prepend a Sun RPC 286 * Record Mark. 287 */ 288 if (!sosendallatonce(so)) { 289 M_PREPEND(mreq, sizeof(u_long), M_WAIT); 290 *mtod(mreq, u_long *) = htonl(0x80000000 | siz); 291 } 292 error = nfs_send(so, nam, mreq, (struct nfsreq *)0); 293 if (nam) 294 m_freem(nam); 295 if (mrep) 296 m_freem(mrep); 297 if (error) { 298 if (error == EPIPE || error == EINTR || 299 error == ERESTART) 300 goto bad; 301 so->so_error = 0; 302 } 303 break; 304 case RC_DROPIT: 305 m_freem(mrep); 306 m_freem(nam); 307 break; 308 }; 309 } 310 bad: 311 return (error); 312 } 313 314 #endif /* NFSSERVER */ 315 316 #ifdef NFSCLIENT 317 318 /* 319 * Nfs pseudo system call for asynchronous i/o daemons. 320 * These babies just pretend to be disk interrupt service routines 321 * for client nfs. They are mainly here for read ahead/write behind. 322 * Never returns unless it fails or gets killed 323 */ 324 /* ARGSUSED */ 325 async_daemon(p, uap, retval) 326 struct proc *p; 327 struct args *uap; 328 int *retval; 329 { 330 register struct buf *bp, *dp; 331 register int i, myiod; 332 int error; 333 334 /* 335 * Must be super user 336 */ 337 if (error = suser(p->p_ucred, &p->p_acflag)) 338 return (error); 339 /* 340 * Assign my position or return error if too many already running 341 */ 342 myiod = -1; 343 for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 344 if (nfs_asyncdaemon[i] == 0) { 345 nfs_asyncdaemon[i]++; 346 myiod = i; 347 break; 348 } 349 if (myiod == -1) 350 return (EBUSY); 351 nfs_numasync++; 352 dp = &nfs_bqueue; 353 /* 354 * Just loop around doin our stuff until SIGKILL 355 */ 356 for (;;) { 357 while (dp->b_actf == NULL && error == 0) { 358 nfs_iodwant[myiod] = p; 359 error = tsleep((caddr_t)&nfs_iodwant[myiod], 360 PWAIT | PCATCH, "nfsidl", 0); 361 nfs_iodwant[myiod] = (struct proc *)0; 362 } 363 while (dp->b_actf != NULL) { 364 /* Take one off the end of the list */ 365 bp = dp->b_actl; 366 if (bp->b_actl == dp) { 367 dp->b_actf = dp->b_actl = (struct buf *)0; 368 } else { 369 dp->b_actl = bp->b_actl; 370 bp->b_actl->b_actf = dp; 371 } 372 (void) nfs_doio(bp); 373 } 374 if (error) { 375 nfs_asyncdaemon[myiod] = 0; 376 nfs_numasync--; 377 return (error); 378 } 379 } 380 } 381 382 #endif /* NFSCLIENT*/ 383 384