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