xref: /original-bsd/sys/nfs/nfs_syscalls.c (revision dfdcf295)
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