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