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