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