xref: /csrg-svn/sys/nfs/nfs_vfsops.c (revision 52196)
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.36 (Berkeley) 01/14/92
11  */
12 
13 #include "param.h"
14 #include "conf.h"
15 #include "ioctl.h"
16 #include "signal.h"
17 #include "proc.h"
18 #include "namei.h"
19 #include "vnode.h"
20 #include "kernel.h"
21 #include "mount.h"
22 #include "buf.h"
23 #include "mbuf.h"
24 #include "socket.h"
25 #include "systm.h"
26 
27 #include "net/if.h"
28 #include "net/route.h"
29 #include "netinet/in.h"
30 
31 #include "rpcv2.h"
32 #include "nfsv2.h"
33 #include "nfsnode.h"
34 #include "nfsmount.h"
35 #include "nfs.h"
36 #include "xdr_subs.h"
37 #include "nfsm_subs.h"
38 #include "nfsdiskless.h"
39 #include "nqnfs.h"
40 
41 /*
42  * nfs vfs operations.
43  */
44 struct vfsops nfs_vfsops = {
45 	nfs_mount,
46 	nfs_start,
47 	nfs_unmount,
48 	nfs_root,
49 	nfs_quotactl,
50 	nfs_statfs,
51 	nfs_sync,
52 	nfs_fhtovp,
53 	nfs_vptofh,
54 	nfs_init,
55 };
56 
57 /*
58  * This structure must be filled in by a primary bootstrap or bootstrap
59  * server for a diskless/dataless machine. It is initialized below just
60  * to ensure that it is allocated to initialized data (.data not .bss).
61  */
62 struct nfs_diskless nfs_diskless = { 0 };
63 
64 static u_char nfs_mntid;
65 extern u_long nfs_procids[NFS_NPROCS];
66 extern u_long nfs_prog, nfs_vers;
67 void nfs_disconnect(), nfsargs_ntoh();
68 
69 #define TRUE	1
70 #define	FALSE	0
71 
72 /*
73  * nfs statfs call
74  */
75 nfs_statfs(mp, sbp, p)
76 	struct mount *mp;
77 	register struct statfs *sbp;
78 	struct proc *p;
79 {
80 	register struct vnode *vp;
81 	register struct nfsv2_statfs *sfp;
82 	register caddr_t cp;
83 	register long t1;
84 	caddr_t bpos, dpos, cp2;
85 	u_long xid;
86 	int error = 0;
87 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
88 	struct nfsmount *nmp;
89 	struct ucred *cred;
90 	struct nfsnode *np;
91 
92 	nmp = VFSTONFS(mp);
93 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
94 		return (error);
95 	vp = NFSTOV(np);
96 	nfsstats.rpccnt[NFSPROC_STATFS]++;
97 	cred = crget();
98 	cred->cr_ngroups = 1;
99 	nfsm_reqhead(vp, NFSPROC_STATFS, NFSX_FH);
100 	nfsm_fhtom(vp);
101 	nfsm_request(vp, NFSPROC_STATFS, p, cred);
102 	nfsm_dissect(sfp, struct nfsv2_statfs *, NFSX_STATFS);
103 	sbp->f_type = MOUNT_NFS;
104 	sbp->f_flags = nmp->nm_flag;
105 	sbp->f_iosize = NFS_MAXDGRAMDATA;
106 	sbp->f_bsize = fxdr_unsigned(long, sfp->sf_bsize);
107 	sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks);
108 	sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree);
109 	sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail);
110 	sbp->f_files = 0;
111 	sbp->f_ffree = 0;
112 	if (sbp != &mp->mnt_stat) {
113 		bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
114 		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
115 	}
116 	nfsm_reqdone;
117 	vrele(vp);
118 	crfree(cred);
119 	return (error);
120 }
121 
122 /*
123  * Mount a remote root fs via. nfs. This depends on the info in the
124  * nfs_diskless structure that has been filled in properly by some primary
125  * bootstrap.
126  * It goes something like this:
127  * - do enough of "ifconfig" by calling ifioctl() so that the system
128  *   can talk to the server
129  * - If nfs_diskless.mygateway is filled in, use that address as
130  *   a default gateway.
131  * - hand craft the swap nfs vnode hanging off a fake mount point
132  *	if swdevt[0].sw_dev == NODEV
133  * - build the rootfs mount point and call mountnfs() to do the rest.
134  */
135 nfs_mountroot()
136 {
137 	register struct mount *mp;
138 	register struct mbuf *m;
139 	struct socket *so;
140 	struct vnode *vp;
141 	int error;
142 
143 	/*
144 	 * Do enough of ifconfig(8) so that the critical net interface can
145 	 * talk to the server.
146 	 */
147 	if (socreate(nfs_diskless.myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0))
148 		panic("nfs ifconf");
149 	if (ifioctl(so, SIOCAIFADDR, &nfs_diskless.myif))
150 		panic("nfs ifconf2");
151 	soclose(so);
152 
153 	/*
154 	 * If the gateway field is filled in, set it as the default route.
155 	 */
156 	if (nfs_diskless.mygateway.sin_len != 0) {
157 		struct sockaddr_in sin;
158 		extern struct sockaddr_in icmpmask;
159 
160 		sin.sin_len = sizeof (struct sockaddr_in);
161 		sin.sin_family = AF_INET;
162 		sin.sin_addr.s_addr = 0;	/* default */
163 		in_sockmaskof(sin.sin_addr, &icmpmask);
164 		if (rtrequest(RTM_ADD, (struct sockaddr *)&sin,
165 			(struct sockaddr *)&nfs_diskless.mygateway,
166 			(struct sockaddr *)&icmpmask,
167 			RTF_UP | RTF_GATEWAY, (struct rtentry **)0))
168 			panic("nfs root route");
169 	}
170 
171 	/*
172 	 * If swapping to an nfs node (indicated by swdevt[0].sw_dev == NODEV):
173 	 * Create a fake mount point just for the swap vnode so that the
174 	 * swap file can be on a different server from the rootfs.
175 	 */
176 	if (swdevt[0].sw_dev == NODEV) {
177 		mp = (struct mount *)malloc((u_long)sizeof(struct mount),
178 			M_MOUNT, M_NOWAIT);
179 		if (mp == NULL)
180 			panic("nfs root mount");
181 		mp->mnt_op = &nfs_vfsops;
182 		mp->mnt_flag = 0;
183 		mp->mnt_mounth = NULLVP;
184 
185 		/*
186 		 * Set up the diskless nfs_args for the swap mount point
187 		 * and then call mountnfs() to mount it.
188 		 * Since the swap file is not the root dir of a file system,
189 		 * hack it to a regular file.
190 		 */
191 		nfs_diskless.swap_args.fh = (nfsv2fh_t *)nfs_diskless.swap_fh;
192 		MGET(m, MT_SONAME, M_DONTWAIT);
193 		if (m == NULL)
194 			panic("nfs root mbuf");
195 		bcopy((caddr_t)&nfs_diskless.swap_saddr, mtod(m, caddr_t),
196 			nfs_diskless.swap_saddr.sin_len);
197 		m->m_len = (int)nfs_diskless.swap_saddr.sin_len;
198 		nfsargs_ntoh(&nfs_diskless.swap_args);
199 		if (mountnfs(&nfs_diskless.swap_args, mp, m, "/swap",
200 			nfs_diskless.swap_hostnam, &vp))
201 			panic("nfs swap");
202 		vp->v_type = VREG;
203 		vp->v_flag = 0;
204 		swapdev_vp = vp;
205 		VREF(vp);
206 		swdevt[0].sw_vp = vp;
207 		swdevt[0].sw_nblks = ntohl(nfs_diskless.swap_nblks);
208 	}
209 
210 	/*
211 	 * Create the rootfs mount point.
212 	 */
213 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
214 		M_MOUNT, M_NOWAIT);
215 	if (mp == NULL)
216 		panic("nfs root mount2");
217 	mp->mnt_op = &nfs_vfsops;
218 	mp->mnt_flag = MNT_RDONLY;
219 	mp->mnt_mounth = NULLVP;
220 
221 	/*
222 	 * Set up the root fs args and call mountnfs() to do the rest.
223 	 */
224 	nfs_diskless.root_args.fh = (nfsv2fh_t *)nfs_diskless.root_fh;
225 	MGET(m, MT_SONAME, M_DONTWAIT);
226 	if (m == NULL)
227 		panic("nfs root mbuf2");
228 	bcopy((caddr_t)&nfs_diskless.root_saddr, mtod(m, caddr_t),
229 		nfs_diskless.root_saddr.sin_len);
230 	m->m_len = (int)nfs_diskless.root_saddr.sin_len;
231 	nfsargs_ntoh(&nfs_diskless.root_args);
232 	if (mountnfs(&nfs_diskless.root_args, mp, m, "/",
233 		nfs_diskless.root_hostnam, &vp))
234 		panic("nfs root");
235 	if (vfs_lock(mp))
236 		panic("nfs root2");
237 	rootfs = mp;
238 	mp->mnt_next = mp;
239 	mp->mnt_prev = mp;
240 	mp->mnt_vnodecovered = NULLVP;
241 	vfs_unlock(mp);
242 	rootvp = vp;
243 	inittodr((time_t)0);	/* There is no time in the nfs fsstat so ?? */
244 	return (0);
245 }
246 
247 /*
248  * Convert the integer fields of the nfs_args structure from net byte order
249  * to host byte order. Called by nfs_mountroot() above.
250  */
251 void
252 nfsargs_ntoh(nfsp)
253 	register struct nfs_args *nfsp;
254 {
255 
256 	NTOHL(nfsp->sotype);
257 	NTOHL(nfsp->proto);
258 	NTOHL(nfsp->flags);
259 	NTOHL(nfsp->wsize);
260 	NTOHL(nfsp->rsize);
261 	NTOHL(nfsp->timeo);
262 	NTOHL(nfsp->retrans);
263 	NTOHL(nfsp->maxgrouplist);
264 	NTOHL(nfsp->readahead);
265 	NTOHL(nfsp->leaseterm);
266 	NTOHL(nfsp->deadthresh);
267 }
268 
269 /*
270  * VFS Operations.
271  *
272  * mount system call
273  * It seems a bit dumb to copyinstr() the host and path here and then
274  * bcopy() them in mountnfs(), but I wanted to detect errors before
275  * doing the sockargs() call because sockargs() allocates an mbuf and
276  * an error after that means that I have to release the mbuf.
277  */
278 /* ARGSUSED */
279 nfs_mount(mp, path, data, ndp, p)
280 	struct mount *mp;
281 	char *path;
282 	caddr_t data;
283 	struct nameidata *ndp;
284 	struct proc *p;
285 {
286 	int error;
287 	struct nfs_args args;
288 	struct mbuf *nam;
289 	struct vnode *vp;
290 	char pth[MNAMELEN], hst[MNAMELEN];
291 	u_int len;
292 	nfsv2fh_t nfh;
293 
294 	if (mp->mnt_flag & MNT_UPDATE)
295 		return (0);
296 	if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)))
297 		return (error);
298 	if (error = copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t)))
299 		return (error);
300 	if (error = copyinstr(path, pth, MNAMELEN-1, &len))
301 		return (error);
302 	bzero(&pth[len], MNAMELEN - len);
303 	if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len))
304 		return (error);
305 	bzero(&hst[len], MNAMELEN - len);
306 	/* sockargs() call must be after above copyin() calls */
307 	if (error = sockargs(&nam, (caddr_t)args.addr,
308 		args.addrlen, MT_SONAME))
309 		return (error);
310 	args.fh = &nfh;
311 	error = mountnfs(&args, mp, nam, pth, hst, &vp);
312 	return (error);
313 }
314 
315 /*
316  * Common code for mount and mountroot
317  */
318 mountnfs(argp, mp, nam, pth, hst, vpp)
319 	register struct nfs_args *argp;
320 	register struct mount *mp;
321 	struct mbuf *nam;
322 	char *pth, *hst;
323 	struct vnode **vpp;
324 {
325 	register struct nfsmount *nmp;
326 	struct nfsnode *np;
327 	int error;
328 	fsid_t tfsid;
329 
330 	MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount), M_NFSMNT,
331 		M_WAITOK);
332 	bzero((caddr_t)nmp, sizeof (struct nfsmount));
333 	mp->mnt_data = (qaddr_t)nmp;
334 	/*
335 	 * Generate a unique nfs mount id. The problem is that a dev number
336 	 * is not unique across multiple systems. The techique is as follows:
337 	 * 1) Set to nblkdev,0 which will never be used otherwise
338 	 * 2) Generate a first guess as nblkdev,nfs_mntid where nfs_mntid is
339 	 *	NOT 0
340 	 * 3) Loop searching the mount list for another one with same id
341 	 *	If a match, increment val[0] and try again
342 	 * NB: I increment val[0] { a long } instead of nfs_mntid { a u_char }
343 	 *	so that nfs is not limited to 255 mount points
344 	 *     Incrementing the high order bits does no real harm, since it
345 	 *     simply makes the major dev number tick up. The upper bound is
346 	 *     set to major dev 127 to avoid any sign extention problems
347 	 */
348 	mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev, 0);
349 	mp->mnt_stat.f_fsid.val[1] = MOUNT_NFS;
350 	if (++nfs_mntid == 0)
351 		++nfs_mntid;
352 	tfsid.val[0] = makedev(nblkdev, nfs_mntid);
353 	tfsid.val[1] = MOUNT_NFS;
354 	while (rootfs && getvfs(&tfsid)) {
355 		tfsid.val[0]++;
356 		nfs_mntid++;
357 	}
358 	if (major(tfsid.val[0]) > 127) {
359 		error = ENOENT;
360 		goto bad;
361 	}
362 	mp->mnt_stat.f_fsid.val[0] = tfsid.val[0];
363 	nmp->nm_mountp = mp;
364 	nmp->nm_flag = argp->flags;
365 	if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_MYWRITE)) ==
366 		(NFSMNT_NQNFS | NFSMNT_MYWRITE)) {
367 		error = EPERM;
368 		goto bad;
369 	}
370 	if ((nmp->nm_flag & (NFSMNT_RDIRALOOK | NFSMNT_LEASETERM)) &&
371 	    (nmp->nm_flag & NFSMNT_NQNFS) == 0) {
372 		error = EPERM;
373 		goto bad;
374 	}
375 	nmp->nm_timeo = NFS_TIMEO;
376 	nmp->nm_retry = NFS_RETRANS;
377 	nmp->nm_wsize = NFS_WSIZE;
378 	nmp->nm_rsize = NFS_RSIZE;
379 	nmp->nm_numgrps = NFS_MAXGRPS;
380 	nmp->nm_readahead = NFS_DEFRAHEAD;
381 	nmp->nm_leaseterm = NQ_DEFLEASE;
382 	nmp->nm_deadthresh = NQ_DEADTHRESH;
383 	nmp->nm_tnext = (struct nfsnode *)nmp;
384 	nmp->nm_tprev = (struct nfsnode *)nmp;
385 	nmp->nm_inprog = NULLVP;
386 	bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t));
387 	mp->mnt_stat.f_type = MOUNT_NFS;
388 	bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
389 	bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN);
390 	nmp->nm_nam = nam;
391 
392 	if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
393 		nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
394 		if (nmp->nm_timeo < NFS_MINTIMEO)
395 			nmp->nm_timeo = NFS_MINTIMEO;
396 		else if (nmp->nm_timeo > NFS_MAXTIMEO)
397 			nmp->nm_timeo = NFS_MAXTIMEO;
398 	}
399 
400 	if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
401 		nmp->nm_retry = argp->retrans;
402 		if (nmp->nm_retry > NFS_MAXREXMIT)
403 			nmp->nm_retry = NFS_MAXREXMIT;
404 	}
405 
406 	if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
407 		nmp->nm_wsize = argp->wsize;
408 		/* Round down to multiple of blocksize */
409 		nmp->nm_wsize &= ~0x1ff;
410 		if (nmp->nm_wsize <= 0)
411 			nmp->nm_wsize = 512;
412 		else if (nmp->nm_wsize > NFS_MAXDATA)
413 			nmp->nm_wsize = NFS_MAXDATA;
414 	}
415 	if (nmp->nm_wsize > MAXBSIZE)
416 		nmp->nm_wsize = MAXBSIZE;
417 
418 	if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
419 		nmp->nm_rsize = argp->rsize;
420 		/* Round down to multiple of blocksize */
421 		nmp->nm_rsize &= ~0x1ff;
422 		if (nmp->nm_rsize <= 0)
423 			nmp->nm_rsize = 512;
424 		else if (nmp->nm_rsize > NFS_MAXDATA)
425 			nmp->nm_rsize = NFS_MAXDATA;
426 	}
427 	if (nmp->nm_rsize > MAXBSIZE)
428 		nmp->nm_rsize = MAXBSIZE;
429 	if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 &&
430 		argp->maxgrouplist <= NFS_MAXGRPS)
431 		nmp->nm_numgrps = argp->maxgrouplist;
432 	if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 &&
433 		argp->readahead <= NFS_MAXRAHEAD)
434 		nmp->nm_readahead = argp->readahead;
435 	if ((argp->flags & NFSMNT_LEASETERM) && argp->leaseterm >= 2 &&
436 		argp->leaseterm <= NQ_MAXLEASE)
437 		nmp->nm_leaseterm = argp->leaseterm;
438 	if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1 &&
439 		argp->deadthresh <= NQ_NEVERDEAD)
440 		nmp->nm_deadthresh = argp->deadthresh;
441 	/* Set up the sockets and per-host congestion */
442 	nmp->nm_sotype = argp->sotype;
443 	nmp->nm_soproto = argp->proto;
444 
445 	/*
446 	 * For Connection based sockets (TCP,...) defer the connect until
447 	 * the first request, in case the server is not responding.
448 	 */
449 	if (nmp->nm_sotype == SOCK_DGRAM &&
450 		(error = nfs_connect(nmp, (struct nfsreq *)0)))
451 		goto bad;
452 
453 	/*
454 	 * This is silly, but it has to be set so that vinifod() works.
455 	 * We do not want to do an nfs_statfs() here since we can get
456 	 * stuck on a dead server and we are holding a lock on the mount
457 	 * point.
458 	 */
459 	mp->mnt_stat.f_iosize = NFS_MAXDGRAMDATA;
460 	/*
461 	 * A reference count is needed on the nfsnode representing the
462 	 * remote root.  If this object is not persistent, then backward
463 	 * traversals of the mount point (i.e. "..") will not work if
464 	 * the nfsnode gets flushed out of the cache. Ufs does not have
465 	 * this problem, because one can identify root inodes by their
466 	 * number == ROOTINO (2).
467 	 */
468 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
469 		goto bad;
470 	*vpp = NFSTOV(np);
471 
472 	return (0);
473 bad:
474 	nfs_disconnect(nmp);
475 	free((caddr_t)nmp, M_NFSMNT);
476 	m_freem(nam);
477 	return (error);
478 }
479 
480 /*
481  * unmount system call
482  */
483 nfs_unmount(mp, mntflags, p)
484 	struct mount *mp;
485 	int mntflags;
486 	struct proc *p;
487 {
488 	register struct nfsmount *nmp;
489 	struct nfsnode *np;
490 	struct vnode *vp;
491 	int error, flags = 0;
492 	extern int doforce;
493 
494 	if (mntflags & MNT_FORCE) {
495 		if (!doforce || mp == rootfs)
496 			return (EINVAL);
497 		flags |= FORCECLOSE;
498 	}
499 	nmp = VFSTONFS(mp);
500 	/*
501 	 * Clear out the buffer cache
502 	 */
503 	mntflushbuf(mp, 0);
504 	if (mntinvalbuf(mp))
505 		return (EBUSY);
506 	/*
507 	 * Goes something like this..
508 	 * - Check for activity on the root vnode (other than ourselves).
509 	 * - Call vflush() to clear out vnodes for this file system,
510 	 *   except for the root vnode.
511 	 * - Decrement reference on the vnode representing remote root.
512 	 * - Close the socket
513 	 * - Free up the data structures
514 	 */
515 	/*
516 	 * We need to decrement the ref. count on the nfsnode representing
517 	 * the remote root.  See comment in mountnfs().  The VFS unmount()
518 	 * has done vput on this vnode, otherwise we would get deadlock!
519 	 */
520 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
521 		return(error);
522 	vp = NFSTOV(np);
523 	if (vp->v_usecount > 2) {
524 		vput(vp);
525 		return (EBUSY);
526 	}
527 
528 	/*
529 	 * Must handshake with nqnfs_clientd() if it is active.
530 	 */
531 	nmp->nm_flag |= NFSMNT_DISMINPROG;
532 	while (nmp->nm_inprog != NULLVP)
533 		(void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0);
534 	if (error = vflush(mp, vp, flags)) {
535 		vput(vp);
536 		nmp->nm_flag &= ~NFSMNT_DISMINPROG;
537 		return (error);
538 	}
539 
540 	/*
541 	 * We are now committed to the unmount.
542 	 * For NQNFS, let the server daemon free the nfsmount structure.
543 	 */
544 	if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB))
545 		nmp->nm_flag |= NFSMNT_DISMNT;
546 
547 	/*
548 	 * There are two reference counts to get rid of here.
549 	 */
550 	vrele(vp);
551 	vrele(vp);
552 	nfs_disconnect(nmp);
553 	m_freem(nmp->nm_nam);
554 
555 	if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) == 0)
556 		free((caddr_t)nmp, M_NFSMNT);
557 	return (0);
558 }
559 
560 /*
561  * Return root of a filesystem
562  */
563 nfs_root(mp, vpp)
564 	struct mount *mp;
565 	struct vnode **vpp;
566 {
567 	register struct vnode *vp;
568 	struct nfsmount *nmp;
569 	struct nfsnode *np;
570 	int error;
571 
572 	nmp = VFSTONFS(mp);
573 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
574 		return (error);
575 	vp = NFSTOV(np);
576 	vp->v_type = VDIR;
577 	vp->v_flag = VROOT;
578 	*vpp = vp;
579 	return (0);
580 }
581 
582 extern int syncprt;
583 
584 /*
585  * Flush out the buffer cache
586  */
587 /* ARGSUSED */
588 nfs_sync(mp, waitfor)
589 	struct mount *mp;
590 	int waitfor;
591 {
592 	if (syncprt)
593 		ufs_bufstats();
594 	/*
595 	 * Force stale buffer cache information to be flushed.
596 	 */
597 	mntflushbuf(mp, waitfor == MNT_WAIT ? B_SYNC : 0);
598 	return (0);
599 }
600 
601 /*
602  * At this point, this should never happen
603  */
604 /* ARGSUSED */
605 nfs_fhtovp(mp, fhp, setgen, vpp)
606 	struct mount *mp;
607 	struct fid *fhp;
608 	int setgen;
609 	struct vnode **vpp;
610 {
611 
612 	return (EINVAL);
613 }
614 
615 /*
616  * Vnode pointer to File handle, should never happen either
617  */
618 /* ARGSUSED */
619 nfs_vptofh(vp, fhp)
620 	struct vnode *vp;
621 	struct fid *fhp;
622 {
623 
624 	return (EINVAL);
625 }
626 
627 /*
628  * Vfs start routine, a no-op.
629  */
630 /* ARGSUSED */
631 nfs_start(mp, flags, p)
632 	struct mount *mp;
633 	int flags;
634 	struct proc *p;
635 {
636 
637 	return (0);
638 }
639 
640 /*
641  * Do operations associated with quotas, not supported
642  */
643 /* ARGSUSED */
644 nfs_quotactl(mp, cmd, uid, arg, p)
645 	struct mount *mp;
646 	int cmd;
647 	u_int uid;
648 	caddr_t arg;
649 	struct proc *p;
650 {
651 
652 	return (EOPNOTSUPP);
653 }
654