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