xref: /original-bsd/sys/nfs/nfs_vfsops.c (revision 04218a6a)
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.20 (Berkeley) 05/04/90
21  */
22 
23 #include "param.h"
24 #include "signal.h"
25 #include "user.h"
26 #include "proc.h"
27 #include "vnode.h"
28 #include "mount.h"
29 #include "errno.h"
30 #include "buf.h"
31 #include "mbuf.h"
32 #include "socket.h"
33 #include "systm.h"
34 #include "nfsv2.h"
35 #include "nfsnode.h"
36 #include "nfsmount.h"
37 #include "nfs.h"
38 
39 /*
40  * nfs vfs operations.
41  */
42 int nfs_mount();
43 int nfs_start();
44 int nfs_unmount();
45 int nfs_root();
46 int nfs_quotactl();
47 int nfs_statfs();
48 int nfs_sync();
49 int nfs_fhtovp();
50 int nfs_vptofh();
51 int nfs_init();
52 
53 struct vfsops nfs_vfsops = {
54 	nfs_mount,
55 	nfs_start,
56 	nfs_unmount,
57 	nfs_root,
58 	nfs_quotactl,
59 	nfs_statfs,
60 	nfs_sync,
61 	nfs_fhtovp,
62 	nfs_vptofh,
63 	nfs_init,
64 };
65 
66 static u_char nfs_mntid;
67 
68 /*
69  * Called by vfs_mountroot when nfs is going to be mounted as root
70  * Not Yet (By a LONG shot)
71  */
72 nfs_mountroot()
73 {
74 	return (ENODEV);
75 }
76 
77 /*
78  * VFS Operations.
79  *
80  * mount system call
81  * It seems a bit dumb to copyinstr() the host and path here and then
82  * bcopy() them in mountnfs(), but I wanted to detect errors before
83  * doing the sockargs() call because sockargs() allocates an mbuf and
84  * an error after that means that I have to release the mbuf.
85  */
86 /* ARGSUSED */
87 nfs_mount(mp, path, data, ndp)
88 	struct mount *mp;
89 	char *path;
90 	caddr_t data;
91 	struct nameidata *ndp;
92 {
93 	int error;
94 	struct nfs_args args;
95 	struct mbuf *saddr;
96 	char pth[MNAMELEN], hst[MNAMELEN];
97 	int len;
98 	nfsv2fh_t nfh;
99 
100 	if (mp->mnt_flag & MNT_UPDATE)
101 		return (0);
102 	if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)))
103 		return (error);
104 	if (error=copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t)))
105 		return (error);
106 	if (error = copyinstr(path, pth, MNAMELEN-1, &len))
107 		return (error);
108 	bzero(&pth[len], MNAMELEN-len);
109 	if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len))
110 		return (error);
111 	bzero(&hst[len], MNAMELEN-len);
112 	/* sockargs() call must be after above copyin() calls */
113 	if (error = sockargs(&saddr, (caddr_t)args.addr,
114 		sizeof (struct sockaddr), MT_SONAME))
115 		return (error);
116 	args.fh = &nfh;
117 	error = mountnfs(&args, mp, saddr, pth, hst);
118 	return (error);
119 }
120 
121 /*
122  * Common code for mount and mountroot
123  */
124 mountnfs(argp, mp, saddr, pth, hst)
125 	register struct nfs_args *argp;
126 	register struct mount *mp;
127 	register struct mbuf *saddr;
128 	char *pth, *hst;
129 {
130 	register struct nfsmount *nmp;
131 	struct nfsnode *np;
132 	int error;
133 	fsid_t tfsid;
134 
135 	MALLOC(nmp, struct nfsmount *, sizeof *nmp, M_NFSMNT, M_WAITOK);
136 	bzero((caddr_t)nmp, sizeof *nmp);
137 	mp->mnt_data = (qaddr_t)nmp;
138 	/*
139 	 * Generate a unique nfs mount id. The problem is that a dev number
140 	 * is not unique across multiple systems. The techique is as follows:
141 	 * 1) Set to nblkdev,0 which will never be used otherwise
142 	 * 2) Generate a first guess as nblkdev,nfs_mntid where nfs_mntid is
143 	 *	NOT 0
144 	 * 3) Loop searching the mount list for another one with same id
145 	 *	If a match, increment val[0] and try again
146 	 * NB: I increment val[0] { a long } instead of nfs_mntid { a u_char }
147 	 *	so that nfs is not limited to 255 mount points
148 	 *     Incrementing the high order bits does no real harm, since it
149 	 *     simply makes the major dev number tick up. The upper bound is
150 	 *     set to major dev 127 to avoid any sign extention problems
151 	 */
152 	mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev, 0);
153 	mp->mnt_stat.f_fsid.val[1] = MOUNT_NFS;
154 	if (++nfs_mntid == 0)
155 		++nfs_mntid;
156 	tfsid.val[0] = makedev(nblkdev, nfs_mntid);
157 	tfsid.val[1] = MOUNT_NFS;
158 	while (getvfs(&tfsid)) {
159 		tfsid.val[0]++;
160 		nfs_mntid++;
161 	}
162 	if (major(tfsid.val[0]) > 127) {
163 		error = ENOENT;
164 		m_freem(saddr);
165 		goto bad;
166 	}
167 	mp->mnt_stat.f_fsid.val[0] = tfsid.val[0];
168 	nmp->nm_mountp = mp;
169 	nmp->nm_flag = argp->flags;
170 	nmp->nm_rto = NFS_TIMEO;
171 	nmp->nm_rtt = -1;
172 	nmp->nm_rttvar = nmp->nm_rto << 1;
173 	nmp->nm_retry = NFS_RETRANS;
174 	nmp->nm_wsize = NFS_WSIZE;
175 	nmp->nm_rsize = NFS_RSIZE;
176 	bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t));
177 	mp->mnt_stat.f_type = MOUNT_NFS;
178 	bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
179 	bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN);
180 
181 	if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
182 		nmp->nm_rto = argp->timeo;
183 		/* NFS timeouts are specified in 1/10 sec. */
184 		nmp->nm_rto = (nmp->nm_rto * 10) / NFS_HZ;
185 		if (nmp->nm_rto < NFS_MINTIMEO)
186 			nmp->nm_rto = NFS_MINTIMEO;
187 		else if (nmp->nm_rto > NFS_MAXTIMEO)
188 			nmp->nm_rto = NFS_MAXTIMEO;
189 		nmp->nm_rttvar = nmp->nm_rto << 1;
190 	}
191 
192 	if ((argp->flags & NFSMNT_RETRANS) && argp->retrans >= 0) {
193 		nmp->nm_retry = argp->retrans;
194 		if (nmp->nm_retry > NFS_MAXREXMIT)
195 			nmp->nm_retry = NFS_MAXREXMIT;
196 	}
197 
198 	if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
199 		nmp->nm_wsize = argp->wsize;
200 		/* Round down to multiple of blocksize */
201 		nmp->nm_wsize &= ~0x1ff;
202 		if (nmp->nm_wsize <= 0)
203 			nmp->nm_wsize = 512;
204 		else if (nmp->nm_wsize > NFS_MAXDATA)
205 			nmp->nm_wsize = NFS_MAXDATA;
206 	}
207 
208 	if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
209 		nmp->nm_rsize = argp->rsize;
210 		/* Round down to multiple of blocksize */
211 		nmp->nm_rsize &= ~0x1ff;
212 		if (nmp->nm_rsize <= 0)
213 			nmp->nm_rsize = 512;
214 		else if (nmp->nm_rsize > NFS_MAXDATA)
215 			nmp->nm_rsize = NFS_MAXDATA;
216 	}
217 	/* Set up the sockets and per-host congestion */
218 	if (error = nfs_connect(nmp, saddr)) {
219 		m_freem(saddr);
220 		goto bad;
221 	}
222 
223 	if (error = nfs_statfs(mp, &mp->mnt_stat))
224 		goto bad;
225 	/*
226 	 * A reference count is needed on the nfsnode representing the
227 	 * remote root.  If this object is not persistent, then backward
228 	 * traversals of the mount point (i.e. "..") will not work if
229 	 * the nfsnode gets flushed out of the cache. Ufs does not have
230 	 * this problem, because one can identify root inodes by their
231 	 * number == ROOTINO (2).
232 	 */
233 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
234 		goto bad;
235 	/*
236 	 * Unlock it, but keep the reference count.
237 	 */
238 	nfs_unlock(NFSTOV(np));
239 	return (0);
240 
241 bad:
242 	nfs_disconnect(nmp);
243 	FREE(nmp, M_NFSMNT);
244 	return (error);
245 }
246 
247 /*
248  * unmount system call
249  */
250 nfs_unmount(mp, mntflags)
251 	struct mount *mp;
252 	int mntflags;
253 {
254 	register struct nfsmount *nmp;
255 	register struct nfsreq *rep;
256 	struct nfsreq *rep2;
257 	struct nfsnode *np;
258 	struct vnode *vp;
259 	int flags = 0;
260 	int error;
261 	int s;
262 
263 	if (mntflags & MNT_FORCE)
264 		return (EINVAL);
265 	if (mntflags & MNT_FORCE)
266 		flags |= FORCECLOSE;
267 	nmp = VFSTONFS(mp);
268 	/*
269 	 * Clear out the buffer cache
270 	 */
271 	mntflushbuf(mp, 0);
272 	if (mntinvalbuf(mp))
273 		return (EBUSY);
274 	/*
275 	 * Goes something like this..
276 	 * - Check for activity on the root vnode (other than ourselves).
277 	 * - Call vflush() to clear out vnodes for this file system,
278 	 *   except for the root vnode.
279 	 * - Decrement reference on the vnode representing remote root.
280 	 * - Close the socket
281 	 * - Free up the data structures
282 	 */
283 	/*
284 	 * We need to decrement the ref. count on the nfsnode representing
285 	 * the remote root.  See comment in mountnfs().  The VFS unmount()
286 	 * has done vput on this vnode, otherwise we would get deadlock!
287 	 */
288 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
289 		return(error);
290 	vp = NFSTOV(np);
291 	if (vp->v_usecount > 2) {
292 		vput(vp);
293 		return (EBUSY);
294 	}
295 	if (error = vflush(mp, vp, flags)) {
296 		vput(vp);
297 		return (error);
298 	}
299 	/*
300 	 * Get rid of two reference counts, and unlock it on the second.
301 	 */
302 	vrele(vp);
303 	vput(vp);
304 	nfs_disconnect(nmp);
305 	free((caddr_t)nmp, M_NFSMNT);
306 	return (0);
307 }
308 
309 /*
310  * Return root of a filesystem
311  */
312 nfs_root(mp, vpp)
313 	struct mount *mp;
314 	struct vnode **vpp;
315 {
316 	register struct vnode *vp;
317 	struct nfsmount *nmp;
318 	struct nfsnode *np;
319 	int error;
320 
321 	nmp = VFSTONFS(mp);
322 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
323 		return (error);
324 	vp = NFSTOV(np);
325 	vp->v_type = VDIR;
326 	vp->v_flag = VROOT;
327 	*vpp = vp;
328 	return (0);
329 }
330 
331 extern int syncprt;
332 
333 /*
334  * Flush out the buffer cache
335  */
336 /* ARGSUSED */
337 nfs_sync(mp, waitfor)
338 	struct mount *mp;
339 	int waitfor;
340 {
341 	if (syncprt)
342 		bufstats();
343 	/*
344 	 * Force stale buffer cache information to be flushed.
345 	 */
346 	mntflushbuf(mp, waitfor == MNT_WAIT ? B_SYNC : 0);
347 	return (0);
348 }
349 
350 /*
351  * At this point, this should never happen
352  */
353 /* ARGSUSED */
354 nfs_fhtovp(mp, fhp, vpp)
355 	struct mount *mp;
356 	struct fid *fhp;
357 	struct vnode **vpp;
358 {
359 
360 	return (EINVAL);
361 }
362 
363 /*
364  * Vnode pointer to File handle, should never happen either
365  */
366 /* ARGSUSED */
367 nfs_vptofh(mp, fhp, vpp)
368 	struct mount *mp;
369 	struct fid *fhp;
370 	struct vnode **vpp;
371 {
372 
373 	return (EINVAL);
374 }
375 
376 /*
377  * Vfs start routine, a no-op.
378  */
379 /* ARGSUSED */
380 nfs_start(mp, flags)
381 	struct mount *mp;
382 	int flags;
383 {
384 
385 	return (0);
386 }
387 
388 /*
389  * Do operations associated with quotas, not supported
390  */
391 /* ARGSUSED */
392 nfs_quotactl(mp, cmd, uid, arg)
393 	struct mount *mp;
394 	int cmd;
395 	uid_t uid;
396 	caddr_t arg;
397 {
398 
399 	return (EOPNOTSUPP);
400 }
401