xref: /original-bsd/sys/nfs/nfs_vfsops.c (revision 753853ba)
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.38 (Berkeley) 02/06/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, i;
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, curproc)) /* XXX */
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 
244 	/*
245 	 * This is not really an nfs issue, but it is much easier to
246 	 * set hostname here and then let the "/etc/rc.xxx" files
247 	 * mount the right /var based upon its preset value.
248 	 */
249 	bcopy(nfs_diskless.my_hostnam, hostname, MAXHOSTNAMELEN);
250 	hostname[MAXHOSTNAMELEN - 1] = '\0';
251 	for (i = 0; i < MAXHOSTNAMELEN; i++)
252 		if (hostname[i] == '\0')
253 			break;
254 	hostnamelen = i;
255 	inittodr((time_t)0);	/* There is no time in the nfs fsstat so ?? */
256 	return (0);
257 }
258 
259 /*
260  * Convert the integer fields of the nfs_args structure from net byte order
261  * to host byte order. Called by nfs_mountroot() above.
262  */
263 void
264 nfsargs_ntoh(nfsp)
265 	register struct nfs_args *nfsp;
266 {
267 
268 	NTOHL(nfsp->sotype);
269 	NTOHL(nfsp->proto);
270 	NTOHL(nfsp->flags);
271 	NTOHL(nfsp->wsize);
272 	NTOHL(nfsp->rsize);
273 	NTOHL(nfsp->timeo);
274 	NTOHL(nfsp->retrans);
275 	NTOHL(nfsp->maxgrouplist);
276 	NTOHL(nfsp->readahead);
277 	NTOHL(nfsp->leaseterm);
278 	NTOHL(nfsp->deadthresh);
279 }
280 
281 /*
282  * VFS Operations.
283  *
284  * mount system call
285  * It seems a bit dumb to copyinstr() the host and path here and then
286  * bcopy() them in mountnfs(), but I wanted to detect errors before
287  * doing the sockargs() call because sockargs() allocates an mbuf and
288  * an error after that means that I have to release the mbuf.
289  */
290 /* ARGSUSED */
291 nfs_mount(mp, path, data, ndp, p)
292 	struct mount *mp;
293 	char *path;
294 	caddr_t data;
295 	struct nameidata *ndp;
296 	struct proc *p;
297 {
298 	int error;
299 	struct nfs_args args;
300 	struct mbuf *nam;
301 	struct vnode *vp;
302 	char pth[MNAMELEN], hst[MNAMELEN];
303 	u_int len;
304 	nfsv2fh_t nfh;
305 
306 	if (mp->mnt_flag & MNT_UPDATE)
307 		return (0);
308 	if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)))
309 		return (error);
310 	if (error = copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t)))
311 		return (error);
312 	if (error = copyinstr(path, pth, MNAMELEN-1, &len))
313 		return (error);
314 	bzero(&pth[len], MNAMELEN - len);
315 	if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len))
316 		return (error);
317 	bzero(&hst[len], MNAMELEN - len);
318 	/* sockargs() call must be after above copyin() calls */
319 	if (error = sockargs(&nam, (caddr_t)args.addr,
320 		args.addrlen, MT_SONAME))
321 		return (error);
322 	args.fh = &nfh;
323 	error = mountnfs(&args, mp, nam, pth, hst, &vp);
324 	return (error);
325 }
326 
327 /*
328  * Common code for mount and mountroot
329  */
330 mountnfs(argp, mp, nam, pth, hst, vpp)
331 	register struct nfs_args *argp;
332 	register struct mount *mp;
333 	struct mbuf *nam;
334 	char *pth, *hst;
335 	struct vnode **vpp;
336 {
337 	register struct nfsmount *nmp;
338 	struct nfsnode *np;
339 	int error;
340 	fsid_t tfsid;
341 
342 	MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount), M_NFSMNT,
343 		M_WAITOK);
344 	bzero((caddr_t)nmp, sizeof (struct nfsmount));
345 	mp->mnt_data = (qaddr_t)nmp;
346 	/*
347 	 * Generate a unique nfs mount id. The problem is that a dev number
348 	 * is not unique across multiple systems. The techique is as follows:
349 	 * 1) Set to nblkdev,0 which will never be used otherwise
350 	 * 2) Generate a first guess as nblkdev,nfs_mntid where nfs_mntid is
351 	 *	NOT 0
352 	 * 3) Loop searching the mount list for another one with same id
353 	 *	If a match, increment val[0] and try again
354 	 * NB: I increment val[0] { a long } instead of nfs_mntid { a u_char }
355 	 *	so that nfs is not limited to 255 mount points
356 	 *     Incrementing the high order bits does no real harm, since it
357 	 *     simply makes the major dev number tick up. The upper bound is
358 	 *     set to major dev 127 to avoid any sign extention problems
359 	 */
360 	mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev, 0);
361 	mp->mnt_stat.f_fsid.val[1] = MOUNT_NFS;
362 	if (++nfs_mntid == 0)
363 		++nfs_mntid;
364 	tfsid.val[0] = makedev(nblkdev, nfs_mntid);
365 	tfsid.val[1] = MOUNT_NFS;
366 	while (rootfs && getvfs(&tfsid)) {
367 		tfsid.val[0]++;
368 		nfs_mntid++;
369 	}
370 	if (major(tfsid.val[0]) > 127) {
371 		error = ENOENT;
372 		goto bad;
373 	}
374 	mp->mnt_stat.f_fsid.val[0] = tfsid.val[0];
375 	nmp->nm_mountp = mp;
376 	nmp->nm_flag = argp->flags;
377 	if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_MYWRITE)) ==
378 		(NFSMNT_NQNFS | NFSMNT_MYWRITE)) {
379 		error = EPERM;
380 		goto bad;
381 	}
382 	if ((nmp->nm_flag & (NFSMNT_RDIRALOOK | NFSMNT_LEASETERM)) &&
383 	    (nmp->nm_flag & NFSMNT_NQNFS) == 0) {
384 		error = EPERM;
385 		goto bad;
386 	}
387 	nmp->nm_timeo = NFS_TIMEO;
388 	nmp->nm_retry = NFS_RETRANS;
389 	nmp->nm_wsize = NFS_WSIZE;
390 	nmp->nm_rsize = NFS_RSIZE;
391 	nmp->nm_numgrps = NFS_MAXGRPS;
392 	nmp->nm_readahead = NFS_DEFRAHEAD;
393 	nmp->nm_leaseterm = NQ_DEFLEASE;
394 	nmp->nm_deadthresh = NQ_DEADTHRESH;
395 	nmp->nm_tnext = (struct nfsnode *)nmp;
396 	nmp->nm_tprev = (struct nfsnode *)nmp;
397 	nmp->nm_inprog = NULLVP;
398 	bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t));
399 	mp->mnt_stat.f_type = MOUNT_NFS;
400 	bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
401 	bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN);
402 	nmp->nm_nam = nam;
403 
404 	if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
405 		nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
406 		if (nmp->nm_timeo < NFS_MINTIMEO)
407 			nmp->nm_timeo = NFS_MINTIMEO;
408 		else if (nmp->nm_timeo > NFS_MAXTIMEO)
409 			nmp->nm_timeo = NFS_MAXTIMEO;
410 	}
411 
412 	if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
413 		nmp->nm_retry = argp->retrans;
414 		if (nmp->nm_retry > NFS_MAXREXMIT)
415 			nmp->nm_retry = NFS_MAXREXMIT;
416 	}
417 
418 	if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
419 		nmp->nm_wsize = argp->wsize;
420 		/* Round down to multiple of blocksize */
421 		nmp->nm_wsize &= ~0x1ff;
422 		if (nmp->nm_wsize <= 0)
423 			nmp->nm_wsize = 512;
424 		else if (nmp->nm_wsize > NFS_MAXDATA)
425 			nmp->nm_wsize = NFS_MAXDATA;
426 	}
427 	if (nmp->nm_wsize > MAXBSIZE)
428 		nmp->nm_wsize = MAXBSIZE;
429 
430 	if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
431 		nmp->nm_rsize = argp->rsize;
432 		/* Round down to multiple of blocksize */
433 		nmp->nm_rsize &= ~0x1ff;
434 		if (nmp->nm_rsize <= 0)
435 			nmp->nm_rsize = 512;
436 		else if (nmp->nm_rsize > NFS_MAXDATA)
437 			nmp->nm_rsize = NFS_MAXDATA;
438 	}
439 	if (nmp->nm_rsize > MAXBSIZE)
440 		nmp->nm_rsize = MAXBSIZE;
441 	if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 &&
442 		argp->maxgrouplist <= NFS_MAXGRPS)
443 		nmp->nm_numgrps = argp->maxgrouplist;
444 	if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 &&
445 		argp->readahead <= NFS_MAXRAHEAD)
446 		nmp->nm_readahead = argp->readahead;
447 	if ((argp->flags & NFSMNT_LEASETERM) && argp->leaseterm >= 2 &&
448 		argp->leaseterm <= NQ_MAXLEASE)
449 		nmp->nm_leaseterm = argp->leaseterm;
450 	if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1 &&
451 		argp->deadthresh <= NQ_NEVERDEAD)
452 		nmp->nm_deadthresh = argp->deadthresh;
453 	/* Set up the sockets and per-host congestion */
454 	nmp->nm_sotype = argp->sotype;
455 	nmp->nm_soproto = argp->proto;
456 
457 	/*
458 	 * For Connection based sockets (TCP,...) defer the connect until
459 	 * the first request, in case the server is not responding.
460 	 */
461 	if (nmp->nm_sotype == SOCK_DGRAM &&
462 		(error = nfs_connect(nmp, (struct nfsreq *)0)))
463 		goto bad;
464 
465 	/*
466 	 * This is silly, but it has to be set so that vinifod() works.
467 	 * We do not want to do an nfs_statfs() here since we can get
468 	 * stuck on a dead server and we are holding a lock on the mount
469 	 * point.
470 	 */
471 	mp->mnt_stat.f_iosize = NFS_MAXDGRAMDATA;
472 	/*
473 	 * A reference count is needed on the nfsnode representing the
474 	 * remote root.  If this object is not persistent, then backward
475 	 * traversals of the mount point (i.e. "..") will not work if
476 	 * the nfsnode gets flushed out of the cache. Ufs does not have
477 	 * this problem, because one can identify root inodes by their
478 	 * number == ROOTINO (2).
479 	 */
480 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
481 		goto bad;
482 	*vpp = NFSTOV(np);
483 
484 	return (0);
485 bad:
486 	nfs_disconnect(nmp);
487 	free((caddr_t)nmp, M_NFSMNT);
488 	m_freem(nam);
489 	return (error);
490 }
491 
492 /*
493  * unmount system call
494  */
495 nfs_unmount(mp, mntflags, p)
496 	struct mount *mp;
497 	int mntflags;
498 	struct proc *p;
499 {
500 	register struct nfsmount *nmp;
501 	struct nfsnode *np;
502 	struct vnode *vp;
503 	int error, flags = 0;
504 	extern int doforce;
505 
506 	if (mntflags & MNT_FORCE) {
507 		if (!doforce || mp == rootfs)
508 			return (EINVAL);
509 		flags |= FORCECLOSE;
510 	}
511 	nmp = VFSTONFS(mp);
512 	/*
513 	 * Clear out the buffer cache
514 	 */
515 	mntflushbuf(mp, 0);
516 	if (mntinvalbuf(mp))
517 		return (EBUSY);
518 	/*
519 	 * Goes something like this..
520 	 * - Check for activity on the root vnode (other than ourselves).
521 	 * - Call vflush() to clear out vnodes for this file system,
522 	 *   except for the root vnode.
523 	 * - Decrement reference on the vnode representing remote root.
524 	 * - Close the socket
525 	 * - Free up the data structures
526 	 */
527 	/*
528 	 * We need to decrement the ref. count on the nfsnode representing
529 	 * the remote root.  See comment in mountnfs().  The VFS unmount()
530 	 * has done vput on this vnode, otherwise we would get deadlock!
531 	 */
532 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
533 		return(error);
534 	vp = NFSTOV(np);
535 	if (vp->v_usecount > 2) {
536 		vput(vp);
537 		return (EBUSY);
538 	}
539 
540 	/*
541 	 * Must handshake with nqnfs_clientd() if it is active.
542 	 */
543 	nmp->nm_flag |= NFSMNT_DISMINPROG;
544 	while (nmp->nm_inprog != NULLVP)
545 		(void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0);
546 	if (error = vflush(mp, vp, flags)) {
547 		vput(vp);
548 		nmp->nm_flag &= ~NFSMNT_DISMINPROG;
549 		return (error);
550 	}
551 
552 	/*
553 	 * We are now committed to the unmount.
554 	 * For NQNFS, let the server daemon free the nfsmount structure.
555 	 */
556 	if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB))
557 		nmp->nm_flag |= NFSMNT_DISMNT;
558 
559 	/*
560 	 * There are two reference counts to get rid of here.
561 	 */
562 	vrele(vp);
563 	vrele(vp);
564 	vgone(vp);
565 	nfs_disconnect(nmp);
566 	m_freem(nmp->nm_nam);
567 
568 	if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) == 0)
569 		free((caddr_t)nmp, M_NFSMNT);
570 	return (0);
571 }
572 
573 /*
574  * Return root of a filesystem
575  */
576 nfs_root(mp, vpp)
577 	struct mount *mp;
578 	struct vnode **vpp;
579 {
580 	register struct vnode *vp;
581 	struct nfsmount *nmp;
582 	struct nfsnode *np;
583 	int error;
584 
585 	nmp = VFSTONFS(mp);
586 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
587 		return (error);
588 	vp = NFSTOV(np);
589 	vp->v_type = VDIR;
590 	vp->v_flag = VROOT;
591 	*vpp = vp;
592 	return (0);
593 }
594 
595 extern int syncprt;
596 
597 /*
598  * Flush out the buffer cache
599  */
600 /* ARGSUSED */
601 nfs_sync(mp, waitfor)
602 	struct mount *mp;
603 	int waitfor;
604 {
605 	if (syncprt)
606 		ufs_bufstats();
607 	/*
608 	 * Force stale buffer cache information to be flushed.
609 	 */
610 	mntflushbuf(mp, waitfor == MNT_WAIT ? B_SYNC : 0);
611 	return (0);
612 }
613 
614 /*
615  * At this point, this should never happen
616  */
617 /* ARGSUSED */
618 nfs_fhtovp(mp, fhp, setgen, vpp)
619 	struct mount *mp;
620 	struct fid *fhp;
621 	int setgen;
622 	struct vnode **vpp;
623 {
624 
625 	return (EINVAL);
626 }
627 
628 /*
629  * Vnode pointer to File handle, should never happen either
630  */
631 /* ARGSUSED */
632 nfs_vptofh(vp, fhp)
633 	struct vnode *vp;
634 	struct fid *fhp;
635 {
636 
637 	return (EINVAL);
638 }
639 
640 /*
641  * Vfs start routine, a no-op.
642  */
643 /* ARGSUSED */
644 nfs_start(mp, flags, p)
645 	struct mount *mp;
646 	int flags;
647 	struct proc *p;
648 {
649 
650 	return (0);
651 }
652 
653 /*
654  * Do operations associated with quotas, not supported
655  */
656 /* ARGSUSED */
657 nfs_quotactl(mp, cmd, uid, arg, p)
658 	struct mount *mp;
659 	int cmd;
660 	u_int uid;
661 	caddr_t arg;
662 	struct proc *p;
663 {
664 
665 	return (EOPNOTSUPP);
666 }
667