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.9 1994/02/14 05:58:29 cgd Exp $ 38 */ 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/kernel.h> 43 #include <sys/file.h> 44 #include <sys/stat.h> 45 #include <sys/namei.h> 46 #include <sys/vnode.h> 47 #include <sys/mount.h> 48 #include <sys/proc.h> 49 #include <sys/malloc.h> 50 #include <sys/buf.h> 51 #include <sys/mbuf.h> 52 #include <sys/socket.h> 53 #include <sys/socketvar.h> 54 #include <sys/domain.h> 55 #include <sys/protosw.h> 56 57 #include <netinet/in.h> 58 #include <netinet/tcp.h> 59 60 #include <nfs/nfsv2.h> 61 #include <nfs/nfs.h> 62 #include <nfs/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 = crdup(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 &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 crfree(cr); 316 return (error); 317 } 318 319 #endif /* NFSSERVER */ 320 321 #ifdef NFSCLIENT 322 323 /* 324 * Nfs pseudo system call for asynchronous i/o daemons. 325 * These babies just pretend to be disk interrupt service routines 326 * for client nfs. They are mainly here for read ahead/write behind. 327 * Never returns unless it fails or gets killed 328 */ 329 /* ARGSUSED */ 330 async_daemon(p, uap, retval) 331 struct proc *p; 332 struct args *uap; 333 int *retval; 334 { 335 register struct buf *bp, *dp; 336 register int i, myiod; 337 int error; 338 339 /* 340 * Must be super user 341 */ 342 if (error = suser(p->p_ucred, &p->p_acflag)) 343 return (error); 344 /* 345 * Assign my position or return error if too many already running 346 */ 347 myiod = -1; 348 for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 349 if (nfs_asyncdaemon[i] == 0) { 350 nfs_asyncdaemon[i]++; 351 myiod = i; 352 break; 353 } 354 if (myiod == -1) 355 return (EBUSY); 356 nfs_numasync++; 357 /* 358 * Just loop around doin our stuff until SIGKILL 359 */ 360 for (;;) { 361 while (nfs_bqueue.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 (nfs_bqueue.b_actf != NULL) { 368 /* Take one off the front of the list */ 369 bp = nfs_bqueue.b_actf; 370 if (dp = bp->b_actf) 371 dp->b_actb = bp->b_actb; 372 else 373 nfs_bqueue.b_actb = bp->b_actb; 374 *bp->b_actb = dp; 375 (void) nfs_doio(bp); 376 } 377 if (error) { 378 nfs_asyncdaemon[myiod] = 0; 379 nfs_numasync--; 380 return (error); 381 } 382 } 383 } 384 385 #endif /* NFSCLIENT*/ 386 387