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