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.5 (Berkeley) 12/20/89 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 /* 51 * NFS server system calls 52 * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c 53 */ 54 #define RETURN(value) { u.u_error = (value); return; } 55 56 /* 57 * Get file handle system call 58 */ 59 getfh() 60 { 61 register struct a { 62 char *fname; 63 fhandle_t *fhp; 64 } *uap = (struct a *)u.u_ap; 65 register struct nameidata *ndp = &u.u_nd; 66 register struct vnode *vp; 67 fhandle_t fh; 68 int error; 69 70 /* 71 * Must be super user 72 */ 73 if (error = suser(u.u_cred, &u.u_acflag)) 74 RETURN (error); 75 ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 76 ndp->ni_segflg = UIO_USERSPACE; 77 ndp->ni_dirp = uap->fname; 78 if (error = namei(ndp)) 79 RETURN (error); 80 vp = ndp->ni_vp; 81 bzero((caddr_t)&fh, sizeof(fh)); 82 fh.fh_fsid = vp->v_mount->m_fsid; 83 error = VFS_VPTOFH(vp, &fh.fh_fid); 84 vput(vp); 85 if (error) 86 RETURN (error); 87 error = copyout((caddr_t)&fh, (caddr_t)uap->fhp, sizeof (fh)); 88 RETURN (error); 89 } 90 91 /* 92 * Mark a mount point in the filesystem exported 93 */ 94 exportfs() 95 { 96 register struct a { 97 char *fname; 98 int rootuid; 99 int exflags; 100 } *uap = (struct a *)u.u_ap; 101 register struct nameidata *ndp = &u.u_nd; 102 register struct vnode *vp; 103 register struct mount *mp; 104 int error; 105 106 /* 107 * Must be super user 108 */ 109 if (error = suser(u.u_cred, &u.u_acflag)) 110 RETURN (error); 111 ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; /* Or NOFOLLOW ?? */ 112 ndp->ni_segflg = UIO_USERSPACE; 113 ndp->ni_dirp = uap->fname; 114 if (error = namei(ndp)) 115 RETURN (error); 116 vp = ndp->ni_vp; 117 if (vp->v_type != VDIR) { 118 vput(vp); 119 RETURN (ENOENT); 120 } 121 mp = vp->v_mount; 122 123 /* 124 * If the filesystem has already been exported, just relax 125 * security as required. 126 * Otherwise export it with the given security 127 */ 128 if (mp->m_flag & M_EXPORTED) { 129 if (uap->rootuid == 0) 130 mp->m_exroot = 0; 131 if ((uap->exflags & M_EXRDONLY) == 0) 132 mp->m_flag &= ~M_EXRDONLY; 133 } else { 134 mp->m_exroot = uap->rootuid; 135 if (uap->exflags & M_EXRDONLY) 136 mp->m_flag |= M_EXRDONLY; 137 mp->m_flag |= M_EXPORTED; 138 } 139 vput(vp); 140 RETURN (0); 141 } 142 143 /* 144 * Nfs server psuedo system call for the nfsd's 145 * Never returns unless it fails or gets killed 146 */ 147 nfssvc() 148 { 149 register struct a { 150 int s; 151 u_long ormask; 152 u_long matchbits; 153 } *uap = (struct a *)u.u_ap; 154 register struct mbuf *m; 155 register int siz; 156 register struct ucred *cr; 157 struct file *fp; 158 struct mbuf *mreq, *mrep, *nam, *md; 159 struct socket *so; 160 caddr_t dpos; 161 int procid; 162 u_long retxid; 163 u_long msk, mtch; 164 int repstat; 165 int error; 166 167 /* 168 * Must be super user 169 */ 170 if (error = suser(u.u_cred, &u.u_acflag)) 171 RETURN (error); 172 fp = getsock(uap->s); 173 if (fp == 0) 174 return; 175 so = (struct socket *)fp->f_data; 176 cr = u.u_cred = crcopy(u.u_cred); /* Copy it so others don't see changes */ 177 msk = uap->ormask; 178 mtch = uap->matchbits; 179 /* 180 * Just loop around doin our stuff until SIGKILL 181 */ 182 for (;;) { 183 if (error = nfs_getreq(so, nfs_prog, nfs_vers, NFS_NPROCS-1, 184 &nam, &mrep, &md, &dpos, &retxid, &procid, cr, msk, mtch)) { 185 m_freem(nam); 186 continue; 187 } 188 switch (nfsrv_getcache(nam, retxid, procid, &mreq)) { 189 case RC_DOIT: 190 if (error = (*(nfsrv_procs[procid]))(mrep, md, dpos, 191 cr, retxid, &mreq, &repstat)) { 192 m_freem(nam); 193 nfsstats.srv_errs++; 194 break; 195 } 196 nfsstats.srvrpccnt[procid]++; 197 nfsrv_updatecache(nam, retxid, procid, repstat, mreq); 198 mrep = (struct mbuf *)0; 199 case RC_REPLY: 200 m = mreq; 201 siz = 0; 202 while (m) { 203 siz += m->m_len; 204 m = m->m_next; 205 } 206 if (siz <= 0 || siz > 9216) { 207 printf("mbuf siz=%d\n",siz); 208 panic("Bad nfs svc reply"); 209 } 210 error = nfs_udpsend(so, nam, mreq, 0, siz); 211 m_freem(nam); 212 if (mrep) 213 m_freem(mrep); 214 break; 215 case RC_DROPIT: 216 m_freem(mrep); 217 m_freem(nam); 218 break; 219 }; 220 } 221 } 222 223 /* 224 * Nfs pseudo system call for asynchronous i/o daemons. 225 * These babies just pretend to be disk interrupt service routines 226 * for client nfs. They are mainly here for read ahead/write behind. 227 * Never returns unless it fails or gets killed 228 */ 229 async_daemon() 230 { 231 register struct buf *bp, *dp; 232 int error; 233 int myiod; 234 235 /* 236 * Must be super user 237 */ 238 if (error = suser(u.u_cred, &u.u_acflag)) 239 RETURN (error); 240 /* 241 * Assign my position or return error if too many already running 242 */ 243 if (nfs_asyncdaemons > MAX_ASYNCDAEMON) 244 RETURN (EBUSY); 245 myiod = nfs_asyncdaemons++; 246 dp = &nfs_bqueue; 247 /* 248 * Just loop around doin our stuff until SIGKILL 249 */ 250 for (;;) { 251 while (dp->b_actf == NULL) { 252 nfs_iodwant[myiod] = u.u_procp; 253 sleep((caddr_t)&nfs_iodwant[myiod], PZERO+1); 254 } 255 /* Take one off the end of the list */ 256 bp = dp->b_actl; 257 if (bp->b_actl == dp) { 258 dp->b_actf = dp->b_actl = (struct buf *)0; 259 } else { 260 dp->b_actl = bp->b_actl; 261 bp->b_actl->b_actf = dp; 262 } 263 (void) nfs_doio(bp); 264 } 265 } 266