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.11 (Berkeley) 04/04/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 "nfsv2.h" 39 #include "nfs.h" 40 #include "nfsrvcache.h" 41 42 /* Global defs. */ 43 extern u_long nfs_prog, nfs_vers; 44 extern int (*nfsrv_procs[NFS_NPROCS])(); 45 extern struct buf nfs_bqueue; 46 extern int nfs_asyncdaemons; 47 extern struct proc *nfs_iodwant[MAX_ASYNCDAEMON]; 48 struct file *getsock(); 49 50 #define TRUE 1 51 #define FALSE 0 52 53 /* 54 * NFS server system calls 55 * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c 56 */ 57 #define RETURN(value) { u.u_error = (value); return; } 58 59 /* 60 * Get file handle system call 61 */ 62 getfh() 63 { 64 register struct a { 65 char *fname; 66 fhandle_t *fhp; 67 } *uap = (struct a *)u.u_ap; 68 register struct nameidata *ndp = &u.u_nd; 69 register struct vnode *vp; 70 fhandle_t fh; 71 int error; 72 73 /* 74 * Must be super user 75 */ 76 if (error = suser(u.u_cred, &u.u_acflag)) 77 RETURN (error); 78 ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 79 ndp->ni_segflg = UIO_USERSPACE; 80 ndp->ni_dirp = uap->fname; 81 if (error = namei(ndp)) 82 RETURN (error); 83 vp = ndp->ni_vp; 84 bzero((caddr_t)&fh, sizeof(fh)); 85 fh.fh_fsid = vp->v_mount->m_stat.f_fsid; 86 error = VFS_VPTOFH(vp, &fh.fh_fid); 87 vput(vp); 88 if (error) 89 RETURN (error); 90 error = copyout((caddr_t)&fh, (caddr_t)uap->fhp, sizeof (fh)); 91 RETURN (error); 92 } 93 94 /* 95 * Nfs server psuedo system call for the nfsd's 96 * Never returns unless it fails or gets killed 97 */ 98 nfssvc() 99 { 100 register struct a { 101 int s; 102 u_long ormask; 103 u_long matchbits; 104 } *uap = (struct a *)u.u_ap; 105 register struct mbuf *m; 106 register int siz; 107 register struct ucred *cr; 108 struct file *fp; 109 struct mbuf *mreq, *mrep, *nam, *md; 110 struct socket *so; 111 caddr_t dpos; 112 int procid; 113 u_long retxid; 114 u_long msk, mtch; 115 int repstat; 116 int error; 117 118 /* 119 * Must be super user 120 */ 121 if (error = suser(u.u_cred, &u.u_acflag)) 122 RETURN (error); 123 fp = getsock(uap->s, &error); 124 if (fp == 0) 125 RETURN (error); 126 so = (struct socket *)fp->f_data; 127 cr = u.u_cred = crcopy(u.u_cred); /* Copy it so others don't see changes */ 128 msk = uap->ormask; 129 mtch = uap->matchbits; 130 /* 131 * Just loop around doin our stuff until SIGKILL 132 */ 133 for (;;) { 134 if (error = nfs_getreq(so, nfs_prog, nfs_vers, NFS_NPROCS-1, 135 &nam, &mrep, &md, &dpos, &retxid, &procid, cr, msk, mtch)) { 136 if (nam) 137 m_freem(nam); 138 if (error == ERESTART || error == EINTR) 139 RETURN (EINTR); 140 continue; 141 } 142 switch (nfsrv_getcache(nam, retxid, procid, &mreq)) { 143 case RC_DOIT: 144 if (error = (*(nfsrv_procs[procid]))(mrep, md, dpos, 145 cr, retxid, &mreq, &repstat)) { 146 nfsrv_updatecache(nam, retxid, procid, 147 FALSE, repstat, mreq); 148 m_freem(nam); 149 nfsstats.srv_errs++; 150 break; 151 } 152 nfsstats.srvrpccnt[procid]++; 153 nfsrv_updatecache(nam, retxid, procid, TRUE, 154 repstat, mreq); 155 mrep = (struct mbuf *)0; 156 case RC_REPLY: 157 m = mreq; 158 siz = 0; 159 while (m) { 160 siz += m->m_len; 161 m = m->m_next; 162 } 163 if (siz <= 0 || siz > 9216) { 164 printf("mbuf siz=%d\n",siz); 165 panic("Bad nfs svc reply"); 166 } 167 error = nfs_send(so, nam, mreq, 0, siz); 168 m_freem(nam); 169 if (mrep) 170 m_freem(mrep); 171 break; 172 case RC_DROPIT: 173 m_freem(mrep); 174 m_freem(nam); 175 break; 176 }; 177 } 178 } 179 180 /* 181 * Nfs pseudo system call for asynchronous i/o daemons. 182 * These babies just pretend to be disk interrupt service routines 183 * for client nfs. They are mainly here for read ahead/write behind. 184 * Never returns unless it fails or gets killed 185 */ 186 async_daemon() 187 { 188 register struct buf *bp, *dp; 189 int error; 190 int myiod; 191 192 /* 193 * Must be super user 194 */ 195 if (error = suser(u.u_cred, &u.u_acflag)) 196 RETURN (error); 197 /* 198 * Assign my position or return error if too many already running 199 */ 200 if (nfs_asyncdaemons > MAX_ASYNCDAEMON) 201 RETURN (EBUSY); 202 myiod = nfs_asyncdaemons++; 203 dp = &nfs_bqueue; 204 /* 205 * Just loop around doin our stuff until SIGKILL 206 */ 207 for (;;) { 208 while (dp->b_actf == NULL) { 209 nfs_iodwant[myiod] = u.u_procp; 210 if (error = tsleep((caddr_t)&nfs_iodwant[myiod], 211 PRIBIO | PCATCH, "nfsidl", 0)) 212 RETURN (error); 213 } 214 /* Take one off the end of the list */ 215 bp = dp->b_actl; 216 if (bp->b_actl == dp) { 217 dp->b_actf = dp->b_actl = (struct buf *)0; 218 } else { 219 dp->b_actl = bp->b_actl; 220 bp->b_actl->b_actf = dp; 221 } 222 (void) nfs_doio(bp); 223 } 224 } 225