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