xref: /csrg-svn/sys/nfs/nfs_vfsops.c (revision 38414)
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_vfsops.c	7.1 (Berkeley) 07/05/89
21  */
22 
23 #include "param.h"
24 #include "signal.h"
25 #include "user.h"
26 #include "proc.h"
27 #include "uio.h"
28 #include "ucred.h"
29 #include "dir.h"
30 #include "namei.h"
31 #include "vnode.h"
32 #include "mount.h"
33 #include "errno.h"
34 #include "malloc.h"
35 #include "mbuf.h"
36 #undef	m_data
37 #include "socket.h"
38 #include "socketvar.h"
39 #include "../netinet/in.h"
40 #include "nfsv2.h"
41 #include "nfsnode.h"
42 #include "nfsmount.h"
43 #include "nfs.h"
44 
45 #ifndef shouldbe
46 #include "conf.h"
47 #endif
48 
49 /*
50  * nfs vfs operations.
51  */
52 int nfs_mount();
53 int nfs_unmount();
54 int nfs_root();
55 extern int nfs_statfs();
56 int nfs_sync();
57 int nfs_fhtovp();
58 int nfs_vptofh();
59 
60 struct vfsops nfs_vfsops = {
61 	nfs_mount,
62 	nfs_unmount,
63 	nfs_root,
64 	nfs_statfs,
65 	nfs_sync,
66 	nfs_fhtovp,
67 	nfs_vptofh,
68 };
69 
70 extern struct nfsreq nfsreqh;
71 static long nfs_mntid;
72 
73 /*
74  * Called by vfs_mountroot when nfs is going to be mounted as root
75  * Not Yet (By a LONG shot)
76  */
77 nfs_mountroot()
78 {
79 	return (ENODEV);
80 }
81 
82 /*
83  * VFS Operations.
84  *
85  * mount system call
86  * It seems a bit dumb to copyinstr() the host and path here and then
87  * bcopy() them in mountnfs(), but I wanted to detect errors before
88  * doing the sockargs() call because sockargs() allocates an mbuf and
89  * an error after that means that I have to release the mbuf.
90  */
91 nfs_mount(mp, path, data, ndp)
92 	struct mount *mp;
93 	char *path;
94 	caddr_t data;
95 	struct nameidata *ndp;
96 {
97 	int error;
98 	struct nfs_args args;
99 	struct mbuf *saddr;
100 	char pth[MNAMELEN], hst[MNAMELEN];
101 	int len;
102 	nfsv2fh_t nfh;
103 
104 	if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)))
105 		return (error);
106 	if (error=copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t)))
107 		return (error);
108 	if (error = copyinstr(path, pth, MNAMELEN-1, &len))
109 		return (error);
110 	bzero(&pth[len], MNAMELEN-len);
111 	if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len))
112 		return (error);
113 	bzero(&hst[len], MNAMELEN-len);
114 	/* sockargs() call must be after above copyin() calls */
115 	if (error = sockargs(&saddr, (caddr_t)args.addr,
116 		sizeof (struct sockaddr_in), MT_SONAME))
117 		return (error);
118 	args.fh = &nfh;
119 	error = mountnfs(&args, mp, saddr, pth, hst);
120 	return (error);
121 }
122 
123 /*
124  * Common code for mount and mountroot
125  */
126 mountnfs(argp, mp, saddr, pth, hst)
127 	register struct nfs_args *argp;
128 	register struct mount *mp;
129 	register struct mbuf *saddr;
130 	char *pth, *hst;
131 {
132 	register struct nfsmount *nmp;
133 	struct nfsnode *np;
134 	struct statfs statf, *sbp;
135 	int error;
136 
137 	nmp = (struct nfsmount *)malloc(sizeof (struct nfsmount), M_NFSMNT,
138 	    M_WAITOK);
139 	mp->m_data = (qaddr_t)nmp;
140 	mp->m_fsid.val[0] = ++nfs_mntid;
141 	mp->m_fsid.val[1] = MOUNT_NFS;
142 	nmp->nm_mountp = mp;
143 	nmp->nm_flag = argp->flags;
144 	nmp->nm_sockaddr = saddr;
145 	/* Set up the sockets */
146 	if (error = socreate(AF_INET, &nmp->nm_so, SOCK_DGRAM, 0))
147 		goto bad;
148 	if (error = soconnect(nmp->nm_so, saddr))
149 		goto bad;
150 	if ((argp->flags & NFSMNT_TIMEO) && argp->timeo >= 1)
151 		nmp->nm_timeo = argp->timeo;
152 	else
153 		nmp->nm_timeo = NFS_TIMEO;
154 	if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 0)
155 		nmp->nm_retrans = argp->retrans;
156 	else
157 		nmp->nm_retrans = NFS_RETRANS;
158 	if ((argp->flags & NFSMNT_WSIZE) &&
159 	    argp->wsize <= NFS_MAXDATA && argp->wsize > 0 &&
160 	   (argp->wsize & 0x1ff) == 0)
161 		nmp->nm_wsize = argp->wsize;
162 	else
163 		nmp->nm_wsize = NFS_WSIZE;
164 	if ((argp->flags & NFSMNT_RSIZE) &&
165 	    argp->rsize <= NFS_MAXDATA && argp->rsize > 0 &&
166 	   (argp->rsize & 0x1ff) == 0)
167 		nmp->nm_rsize = argp->rsize;
168 	else
169 		nmp->nm_rsize = NFS_RSIZE;
170 	bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t));
171 	bcopy(pth, nmp->nm_path, MNAMELEN);
172 	bcopy(hst, nmp->nm_host, MNAMELEN);
173 	sbp = &statf;
174 	/*
175 	 * Kludge City...
176 	 * To do an interruptable hard mount, turn it into a soft mount
177 	 * with a retry limit of one and then repeat it so long as it
178 	 * times out and there is no pending signal for the process.
179 	 * It is tempting to just let nfs_statfs() sleep at positive
180 	 * prio, but then you would long jump out without taking the
181 	 * mount structure back out of the list.
182 	 * NB: NFSMNT_INT must NEVER be set for nfs_mountroot(), since
183 	 * the process context is not yet built!!
184 	 */
185 	if ((argp->flags && NFSMNT_INT) && (argp->flags & NFSMNT_SOFT) == 0) {
186 		int savretrans;
187 
188 		nmp->nm_flag |= NFSMNT_SOFT;
189 		savretrans = nmp->nm_retrans;
190 		nmp->nm_retrans = 1;
191 		do {
192 			error = nfs_statfs(mp, sbp);
193 		} while (error == ETIMEDOUT && (u.u_procp->p_sig &
194 			(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM)|
195 			 sigmask(SIGKILL))) == 0);
196 		nmp->nm_retrans = savretrans;
197 		nmp->nm_flag &= ~NFSMNT_SOFT;
198 		if (error)
199 			goto bad;
200 	} else if (error = nfs_statfs(mp, sbp))
201 		goto bad;
202 	mp->m_fsize = sbp->f_fsize;
203 
204 	/*
205 	 * If the block size is not an exact multiple of CLBYTES
206 	 * use CLBYTES so that paging in ZMAGIC executables doesn't
207 	 * get sick. (It is used by vinitfod())
208 	 */
209 	if (sbp->f_bsize >= CLBYTES && claligned(sbp->f_bsize))
210 		mp->m_bsize = sbp->f_bsize;
211 	else
212 		mp->m_bsize = CLBYTES;
213 	return (0);
214 bad:
215 	m_freem(saddr);
216 	free((caddr_t)nmp, M_NFSMNT);
217 	return (error);
218 }
219 
220 /*
221  * unmount system call
222  */
223 nfs_unmount(mp, flags)
224 	struct mount *mp;
225 	int flags;
226 {
227 	register struct nfsmount *nmp;
228 	register struct nfsreq *rep;
229 	struct nfsreq *rep2;
230 	int error;
231 	int s;
232 
233 	if (flags & MNT_FORCE)
234 		return (EINVAL);
235 	nmp = vfs_to_nfs(mp);
236 	/*
237 	 * Goes something like this..
238 	 * - Call nfs_nflush() to clear out the nfsnode table
239 	 * - Flush out lookup cache
240 	 * - Close the socket
241 	 * - Free up the data structures
242 	 */
243 	if (error = nfs_nflush(mp)) {
244 		return (error);
245 	}
246 	/*
247 	 * Scan the request list for any requests left hanging about
248 	 */
249 	s = splnet();
250 	rep = nfsreqh.r_next;
251 	while (rep) {
252 		if (rep->r_mntp == nmp) {
253 			rep->r_prev->r_next = rep2 = rep->r_next;
254 			if (rep->r_next != NULL)
255 				rep->r_next->r_prev = rep->r_prev;
256 			m_freem(rep->r_mreq);
257 			if (rep->r_mrep != NULL)
258 				m_freem(rep->r_mrep);
259 			free((caddr_t)rep, M_NFSREQ);
260 			rep = rep2;
261 		} else
262 			rep = rep->r_next;
263 	}
264 	splx(s);
265 	soclose(nmp->nm_so);
266 	m_freem(nmp->nm_sockaddr);
267 	free((caddr_t)nmp, M_NFSMNT);
268 	return (0);
269 }
270 
271 /*
272  * Return root of a filesystem
273  */
274 nfs_root(mp, vpp)
275 	struct mount *mp;
276 	struct vnode **vpp;
277 {
278 	register struct vnode *vp;
279 	struct nfsmount *nmp;
280 	struct nfsnode *np;
281 	int error;
282 
283 	nmp = vfs_to_nfs(mp);
284 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
285 		return (error);
286 	vp = NFSTOV(np);
287 	vp->v_type = VDIR;
288 	vp->v_flag = VROOT;
289 	*vpp = vp;
290 	return (0);
291 }
292 
293 /*
294  * Since writes are synchronous, I think this is a no-op
295  * Maybe write cache on nfs version 3 will require something ??
296  */
297 nfs_sync(mp, waitfor)
298 	struct mount *mp;
299 	int waitfor;
300 {
301 	return (0);
302 }
303 
304 /*
305  * At this point, this should never happen
306  */
307 nfs_fhtovp(mp, fhp, vpp)
308 	struct mount *mp;
309 	struct fid *fhp;
310 	struct vnode **vpp;
311 {
312 	return (EINVAL);
313 }
314 
315 /*
316  * Vnode pointer to File handle, should never happen either
317  */
318 nfs_vptofh(mp, fhp, vpp)
319 	struct mount *mp;
320 	struct fid *fhp;
321 	struct vnode **vpp;
322 {
323 	return (EINVAL);
324 }
325