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 are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the University of California, Berkeley. The name of the 14 * University may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * @(#)nfs_syscalls.c 7.16 (Berkeley) 06/21/90 21 */ 22 23 #include "param.h" 24 #include "systm.h" 25 #include "syscontext.h" 26 #include "kernel.h" 27 #include "file.h" 28 #include "stat.h" 29 #include "vnode.h" 30 #include "mount.h" 31 #include "proc.h" 32 #include "uio.h" 33 #include "malloc.h" 34 #include "buf.h" 35 #include "mbuf.h" 36 #include "socket.h" 37 #include "socketvar.h" 38 #include "domain.h" 39 #include "protosw.h" 40 #include "../netinet/in.h" 41 #include "../netinet/tcp.h" 42 #include "nfsv2.h" 43 #include "nfs.h" 44 #include "nfsrvcache.h" 45 46 /* Global defs. */ 47 extern u_long nfs_prog, nfs_vers; 48 extern int (*nfsrv_procs[NFS_NPROCS])(); 49 extern struct buf nfs_bqueue; 50 extern int nfs_asyncdaemons; 51 extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 52 extern int nfs_tcpnodelay; 53 struct file *getsock(); 54 55 #define TRUE 1 56 #define FALSE 0 57 58 /* 59 * NFS server system calls 60 * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c 61 */ 62 63 /* 64 * Get file handle system call 65 */ 66 /* ARGSUSED */ 67 getfh(p, uap, retval) 68 struct proc *p; 69 register struct args { 70 char *fname; 71 fhandle_t *fhp; 72 } *uap; 73 int *retval; 74 { 75 register struct nameidata *ndp = &u.u_nd; 76 register struct vnode *vp; 77 fhandle_t fh; 78 int error; 79 80 /* 81 * Must be super user 82 */ 83 if (error = suser(ndp->ni_cred, &u.u_acflag)) 84 RETURN (error); 85 ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 86 ndp->ni_segflg = UIO_USERSPACE; 87 ndp->ni_dirp = uap->fname; 88 if (error = namei(ndp)) 89 RETURN (error); 90 vp = ndp->ni_vp; 91 bzero((caddr_t)&fh, sizeof(fh)); 92 fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid; 93 error = VFS_VPTOFH(vp, &fh.fh_fid); 94 vput(vp); 95 if (error) 96 RETURN (error); 97 error = copyout((caddr_t)&fh, (caddr_t)uap->fhp, sizeof (fh)); 98 RETURN (error); 99 } 100 101 /* 102 * Nfs server psuedo system call for the nfsd's 103 * Never returns unless it fails or gets killed 104 */ 105 /* ARGSUSED */ 106 nfssvc(p, uap, retval) 107 struct proc *p; 108 register struct args { 109 int s; 110 caddr_t mskval; 111 int msklen; 112 caddr_t mtchval; 113 int mtchlen; 114 } *uap; 115 int *retval; 116 { 117 register struct mbuf *m; 118 register int siz; 119 register struct ucred *cr; 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; 126 u_long retxid; 127 128 /* 129 * Must be super user 130 */ 131 if (error = suser(u.u_cred, &u.u_acflag)) 132 goto bad; 133 fp = getsock(uap->s); 134 if (fp == 0) 135 return; 136 so = (struct socket *)fp->f_data; 137 if (sosendallatonce(so)) 138 siz = NFS_MAXPACKET; 139 else 140 siz = NFS_MAXPACKET + sizeof(u_long); 141 if (error = soreserve(so, siz, siz)) 142 goto bad; 143 if (error = sockargs(&nam, uap->mskval, uap->msklen, MT_SONAME)) 144 goto bad; 145 bcopy((caddr_t)nam, (caddr_t)&msk, sizeof (struct mbuf)); 146 msk.m_data = msk.m_dat; 147 m_freem(nam); 148 if (error = sockargs(&nam, uap->mtchval, uap->mtchlen, MT_SONAME)) 149 goto bad; 150 bcopy((caddr_t)nam, (caddr_t)&mtch, sizeof (struct mbuf)); 151 mtch.m_data = mtch.m_dat; 152 m_freem(nam); 153 154 /* Copy the cred so others don't see changes */ 155 cr = u.u_cred = crcopy(u.u_cred); 156 157 /* 158 * Set protocol specific options { for now TCP only } and 159 * reserve some space. For datagram sockets, this can get called 160 * repeatedly for the same socket, but that isn't harmful. 161 */ 162 if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 163 MGET(m, M_WAIT, MT_SOOPTS); 164 *mtod(m, int *) = 1; 165 m->m_len = sizeof(int); 166 sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m); 167 } 168 if (so->so_proto->pr_domain->dom_family == AF_INET && 169 so->so_proto->pr_protocol == IPPROTO_TCP && 170 nfs_tcpnodelay) { 171 MGET(m, M_WAIT, MT_SOOPTS); 172 *mtod(m, int *) = 1; 173 m->m_len = sizeof(int); 174 sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m); 175 } 176 so->so_rcv.sb_flags &= ~SB_NOINTR; 177 so->so_rcv.sb_timeo = 0; 178 so->so_snd.sb_flags &= ~SB_NOINTR; 179 so->so_snd.sb_timeo = 0; 180 181 /* 182 * Just loop around doin our stuff until SIGKILL 183 */ 184 for (;;) { 185 if (error = nfs_getreq(so, nfs_prog, nfs_vers, NFS_NPROCS-1, 186 &nam, &mrep, &md, &dpos, &retxid, &procid, cr, 187 &msk, &mtch)) { 188 if (nam) 189 m_freem(nam); 190 if (error == EPIPE || error == EINTR || 191 error == ERESTART) { 192 error = 0; 193 goto bad; 194 } 195 so->so_error = 0; 196 continue; 197 } 198 199 if (nam) 200 cacherep = nfsrv_getcache(nam, retxid, procid, &mreq); 201 else 202 cacherep = RC_DOIT; 203 switch (cacherep) { 204 case RC_DOIT: 205 if (error = (*(nfsrv_procs[procid]))(mrep, md, dpos, 206 cr, retxid, &mreq, &repstat)) { 207 nfsstats.srv_errs++; 208 if (nam) { 209 nfsrv_updatecache(nam, retxid, procid, 210 FALSE, repstat, mreq); 211 m_freem(nam); 212 } 213 break; 214 } 215 nfsstats.srvrpccnt[procid]++; 216 if (nam) 217 nfsrv_updatecache(nam, retxid, procid, TRUE, 218 repstat, mreq); 219 mrep = (struct mbuf *)0; 220 case RC_REPLY: 221 m = mreq; 222 siz = 0; 223 while (m) { 224 siz += m->m_len; 225 m = m->m_next; 226 } 227 if (siz <= 0 || siz > NFS_MAXPACKET) { 228 printf("mbuf siz=%d\n",siz); 229 panic("Bad nfs svc reply"); 230 } 231 mreq->m_pkthdr.len = siz; 232 mreq->m_pkthdr.rcvif = (struct ifnet *)0; 233 /* 234 * For non-atomic protocols, prepend a Sun RPC 235 * Record Mark. 236 */ 237 if (!sosendallatonce(so)) { 238 M_PREPEND(mreq, sizeof(u_long), M_WAIT); 239 *mtod(mreq, u_long *) = htonl(0x80000000 | siz); 240 } 241 error = nfs_send(so, nam, mreq, (struct nfsreq *)0); 242 if (nam) 243 m_freem(nam); 244 if (mrep) 245 m_freem(mrep); 246 if (error) { 247 if (error == EPIPE || error == EINTR || 248 error == ERESTART) 249 goto bad; 250 so->so_error = 0; 251 } 252 break; 253 case RC_DROPIT: 254 m_freem(mrep); 255 m_freem(nam); 256 break; 257 }; 258 } 259 bad: 260 RETURN (error); 261 } 262 263 /* 264 * Nfs pseudo system call for asynchronous i/o daemons. 265 * These babies just pretend to be disk interrupt service routines 266 * for client nfs. They are mainly here for read ahead/write behind. 267 * Never returns unless it fails or gets killed 268 */ 269 /* ARGSUSED */ 270 async_daemon(p, uap, retval) 271 struct proc *p; 272 struct args *uap; 273 int *retval; 274 { 275 register struct buf *bp, *dp; 276 int error; 277 int myiod; 278 279 /* 280 * Must be super user 281 */ 282 if (error = suser(u.u_cred, &u.u_acflag)) 283 RETURN (error); 284 /* 285 * Assign my position or return error if too many already running 286 */ 287 if (nfs_asyncdaemons > NFS_MAXASYNCDAEMON) 288 RETURN (EBUSY); 289 myiod = nfs_asyncdaemons++; 290 dp = &nfs_bqueue; 291 /* 292 * Just loop around doin our stuff until SIGKILL 293 */ 294 for (;;) { 295 while (dp->b_actf == NULL) { 296 nfs_iodwant[myiod] = p; 297 if (error = tsleep((caddr_t)&nfs_iodwant[myiod], 298 PWAIT | PCATCH, "nfsidl", 0)) 299 RETURN (error); 300 } 301 /* Take one off the end of the list */ 302 bp = dp->b_actl; 303 if (bp->b_actl == dp) { 304 dp->b_actf = dp->b_actl = (struct buf *)0; 305 } else { 306 dp->b_actl = bp->b_actl; 307 bp->b_actl->b_actf = dp; 308 } 309 (void) nfs_doio(bp); 310 } 311 } 312