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.14 (Berkeley) 05/14/90 21 */ 22 23 #include "param.h" 24 #include "systm.h" 25 #include "user.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 #define RETURN(value) { u.u_error = (value); return; } 63 64 /* 65 * Get file handle system call 66 */ 67 getfh() 68 { 69 register struct a { 70 char *fname; 71 fhandle_t *fhp; 72 } *uap = (struct a *)u.u_ap; 73 register struct nameidata *ndp = &u.u_nd; 74 register struct vnode *vp; 75 fhandle_t fh; 76 int error; 77 78 /* 79 * Must be super user 80 */ 81 if (error = suser(u.u_cred, &u.u_acflag)) 82 RETURN (error); 83 ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 84 ndp->ni_segflg = UIO_USERSPACE; 85 ndp->ni_dirp = uap->fname; 86 if (error = namei(ndp)) 87 RETURN (error); 88 vp = ndp->ni_vp; 89 bzero((caddr_t)&fh, sizeof(fh)); 90 fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid; 91 error = VFS_VPTOFH(vp, &fh.fh_fid); 92 vput(vp); 93 if (error) 94 RETURN (error); 95 error = copyout((caddr_t)&fh, (caddr_t)uap->fhp, sizeof (fh)); 96 RETURN (error); 97 } 98 99 /* 100 * Nfs server psuedo system call for the nfsd's 101 * Never returns unless it fails or gets killed 102 */ 103 nfssvc() 104 { 105 register struct a { 106 int s; 107 caddr_t mskval; 108 int msklen; 109 caddr_t mtchval; 110 int mtchlen; 111 } *uap = (struct a *)u.u_ap; 112 register struct mbuf *m; 113 register int siz; 114 register struct ucred *cr; 115 struct file *fp; 116 struct mbuf *mreq, *mrep, *nam, *md; 117 struct mbuf msk, mtch; 118 struct socket *so; 119 caddr_t dpos; 120 int procid, repstat, error, cacherep, solock = 0; 121 u_long retxid; 122 123 /* 124 * Must be super user 125 */ 126 if (error = suser(u.u_cred, &u.u_acflag)) 127 goto bad; 128 fp = getsock(uap->s); 129 if (fp == 0) 130 return; 131 so = (struct socket *)fp->f_data; 132 if (sosendallatonce(so)) 133 siz = NFS_MAXPACKET; 134 else 135 siz = NFS_MAXPACKET + sizeof(u_long); 136 if (error = soreserve(so, siz, siz * 4)) 137 goto bad; 138 if (error = sockargs(&nam, uap->mskval, uap->msklen, MT_SONAME)) 139 goto bad; 140 bcopy((caddr_t)nam, (caddr_t)&msk, sizeof (struct mbuf)); 141 msk.m_data = msk.m_dat; 142 m_freem(nam); 143 if (error = sockargs(&nam, uap->mtchval, uap->mtchlen, MT_SONAME)) 144 goto bad; 145 bcopy((caddr_t)nam, (caddr_t)&mtch, sizeof (struct mbuf)); 146 mtch.m_data = mtch.m_dat; 147 m_freem(nam); 148 149 /* Copy the cred so others don't see changes */ 150 cr = u.u_cred = crcopy(u.u_cred); 151 152 /* 153 * Set protocol specific options { for now TCP only } and 154 * reserve some space. For datagram sockets, this can get called 155 * repeatedly for the same socket, but that isn't harmful. 156 */ 157 if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 158 MGET(m, M_WAIT, MT_SOOPTS); 159 *mtod(m, int *) = 1; 160 m->m_len = sizeof(int); 161 sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m); 162 } 163 if (so->so_proto->pr_domain->dom_family == AF_INET && 164 so->so_proto->pr_protocol == IPPROTO_TCP && 165 nfs_tcpnodelay) { 166 MGET(m, M_WAIT, MT_SOOPTS); 167 *mtod(m, int *) = 1; 168 m->m_len = sizeof(int); 169 sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m); 170 } 171 so->so_rcv.sb_flags &= ~SB_NOINTR; 172 so->so_rcv.sb_timeo = 0; 173 so->so_snd.sb_flags &= ~SB_NOINTR; 174 so->so_snd.sb_timeo = 0; 175 176 /* 177 * Just loop around doin our stuff until SIGKILL 178 */ 179 for (;;) { 180 if (error = nfs_getreq(so, nfs_prog, nfs_vers, NFS_NPROCS-1, 181 &nam, &mrep, &md, &dpos, &retxid, &procid, cr, &solock, 182 &msk, &mtch)) { 183 if (nam) 184 m_freem(nam); 185 if (error == EPIPE || error == EINTR || 186 error == ERESTART) 187 goto bad; 188 so->so_error = 0; 189 continue; 190 } 191 192 if (nam) 193 cacherep = nfsrv_getcache(nam, retxid, procid, &mreq); 194 else 195 cacherep = RC_DOIT; 196 switch (cacherep) { 197 case RC_DOIT: 198 if (error = (*(nfsrv_procs[procid]))(mrep, md, dpos, 199 cr, retxid, &mreq, &repstat)) { 200 nfsstats.srv_errs++; 201 if (nam) { 202 nfsrv_updatecache(nam, retxid, procid, 203 FALSE, repstat, mreq); 204 m_freem(nam); 205 } 206 break; 207 } 208 nfsstats.srvrpccnt[procid]++; 209 if (nam) 210 nfsrv_updatecache(nam, retxid, procid, TRUE, 211 repstat, mreq); 212 mrep = (struct mbuf *)0; 213 case RC_REPLY: 214 m = mreq; 215 siz = 0; 216 while (m) { 217 siz += m->m_len; 218 m = m->m_next; 219 } 220 if (siz <= 0 || siz > NFS_MAXPACKET) { 221 printf("mbuf siz=%d\n",siz); 222 panic("Bad nfs svc reply"); 223 } 224 mreq->m_pkthdr.len = siz; 225 mreq->m_pkthdr.rcvif = (struct ifnet *)0; 226 /* 227 * For non-atomic protocols, prepend a Sun RPC 228 * Record Mark. 229 */ 230 if (!sosendallatonce(so)) { 231 M_PREPEND(mreq, sizeof(u_long), M_WAIT); 232 *mtod(mreq, u_long *) = htonl(0x80000000 | siz); 233 } 234 if (so->so_proto->pr_flags & PR_CONNREQUIRED) 235 nfs_solock(&solock, 0); 236 error = nfs_send(so, nam, mreq, (struct nfsreq *)0); 237 if (so->so_proto->pr_flags & PR_CONNREQUIRED) 238 nfs_sounlock(&solock); 239 if (nam) 240 m_freem(nam); 241 if (mrep) 242 m_freem(mrep); 243 if (error) { 244 if (error == EPIPE || error == EINTR || 245 error == ERESTART) 246 goto bad; 247 so->so_error = 0; 248 } 249 break; 250 case RC_DROPIT: 251 m_freem(mrep); 252 m_freem(nam); 253 break; 254 }; 255 } 256 bad: 257 RETURN (error); 258 } 259 260 /* 261 * Nfs pseudo system call for asynchronous i/o daemons. 262 * These babies just pretend to be disk interrupt service routines 263 * for client nfs. They are mainly here for read ahead/write behind. 264 * Never returns unless it fails or gets killed 265 */ 266 async_daemon() 267 { 268 register struct buf *bp, *dp; 269 int error; 270 int myiod; 271 272 /* 273 * Must be super user 274 */ 275 if (error = suser(u.u_cred, &u.u_acflag)) 276 RETURN (error); 277 /* 278 * Assign my position or return error if too many already running 279 */ 280 if (nfs_asyncdaemons > NFS_MAXASYNCDAEMON) 281 RETURN (EBUSY); 282 myiod = nfs_asyncdaemons++; 283 dp = &nfs_bqueue; 284 /* 285 * Just loop around doin our stuff until SIGKILL 286 */ 287 for (;;) { 288 while (dp->b_actf == NULL) { 289 nfs_iodwant[myiod] = u.u_procp; 290 if (error = tsleep((caddr_t)&nfs_iodwant[myiod], 291 PWAIT | PCATCH, "nfsidl", 0)) 292 RETURN (error); 293 } 294 /* Take one off the end of the list */ 295 bp = dp->b_actl; 296 if (bp->b_actl == dp) { 297 dp->b_actf = dp->b_actl = (struct buf *)0; 298 } else { 299 dp->b_actl = bp->b_actl; 300 bp->b_actl->b_actf = dp; 301 } 302 (void) nfs_doio(bp); 303 } 304 } 305