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