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