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