xref: /386bsd/usr/src/kernel/nfs/nfs_vfsops.c (revision dc8b130e)
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, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  *	$Id: nfs_vfsops.c,v 1.1 94/10/20 10:57:36 root Exp Locker: bill $
37  */
38 
39 static char *nfs_config = "nfs 2. # Sun Network Filesystem (NFS) $Revision$";
40 /* static char *nfs_config = "nfs 2 ((udp 111) (tcp 111))."; */
41 
42 #include "sys/param.h"
43 #include "sys/ioctl.h"
44 #include "sys/signal.h"
45 #include "sys/file.h"
46 #include "sys/mount.h"
47 #include "sys/errno.h"
48 #include "proc.h"
49 #include "buf.h"
50 #include "uio.h"
51 #include "systm.h"	/* rootvp ... */
52 #include "machine/cpu.h"	/* inittodr() */
53 #include "modconfig.h"
54 
55 #include "mbuf.h"
56 #include "socketvar.h"
57 #include "if.h"
58 #include "route.h"
59 #include "in.h"
60 
61 #include "vnode.h"
62 #include "namei.h"
63 #include "nfs_v2.h"
64 #include "nfs_node.h"
65 #include "nfs_mount.h"
66 #include "nfs.h"
67 #include "nfs_xdr_subs.h"
68 #include "nfs_msubs.h"
69 #include "nfs_diskless.h"
70 
71 #include "prototypes.h"
72 
73 int nfs_mountroot(); /* XXX */
74 int zero;
75 
76 /*
77  * nfs vfs operations.
78  */
79 struct vfsops nfs_vfsops = {
80 	"nfs", 0, 0,
81 	nfs_mount,
82 	nfs_start,
83 	nfs_unmount,
84 	nfs_root,
85 	nfs_quotactl,
86 	nfs_statfs,
87 	nfs_sync,
88 	nfs_fhtovp,
89 	nfs_vptofh,
90 	nfs_init,
91 	nfs_mountroot,
92 };
93 
FILESYSTEM_MODCONFIG()94 FILESYSTEM_MODCONFIG() {
95 	char *cfg_string = nfs_config;
96 
97 	if (config_scan(nfs_config, &cfg_string) == 0)
98 		return;
99 	if (cfg_number(&cfg_string, &nfs_vfsops.vfs_type) == 0)
100 		return;
101 
102 	addvfs(&nfs_vfsops);
103 	nfs_init();
104 }
105 
106 static u_char nfs_mntid;
107 extern u_long nfs_procids[NFS_NPROCS];
108 extern u_long nfs_prog, nfs_vers;
109 struct nfs_diskless nfs_diskless;
110 void nfs_disconnect();
111 
112 #define TRUE	1
113 #define	FALSE	0
114 
115 /*
116  * nfs statfs call
117  */
118 nfs_statfs(mp, sbp, p)
119 	struct mount *mp;
120 	register struct statfs *sbp;
121 	struct proc *p;
122 {
123 	register struct vnode *vp;
124 	register struct nfsv2_statfs *sfp;
125 	register caddr_t cp;
126 	register long t1;
127 	caddr_t bpos, dpos, cp2;
128 	u_long xid;
129 	int error = 0;
130 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
131 	struct nfsmount *nmp;
132 	struct ucred *cred;
133 	struct nfsnode *np;
134 
135 	nmp = VFSTONFS(mp);
136 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
137 		return (error);
138 	vp = NFSTOV(np);
139 	nfsstats.rpccnt[NFSPROC_STATFS]++;
140 	cred = crget();
141 	cred->cr_ngroups = 1;
142 	nfsm_reqhead(nfs_procids[NFSPROC_STATFS], cred, NFSX_FH);
143 	nfsm_fhtom(vp);
144 	nfsm_request(vp, NFSPROC_STATFS, p, 0);
145 	nfsm_disect(sfp, struct nfsv2_statfs *, NFSX_STATFS);
146 	sbp->f_type = MOUNT_NFS;
147 	sbp->f_flags = nmp->nm_flag;
148 	sbp->f_bsize = fxdr_unsigned(long, sfp->sf_tsize);
149 	sbp->f_fsize = fxdr_unsigned(long, sfp->sf_bsize);
150 	sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks);
151 	sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree);
152 	sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail);
153 	sbp->f_files = 0;
154 	sbp->f_ffree = 0;
155 	if (sbp != &mp->mnt_stat) {
156 		memcpy(sbp->f_mntonname, mp->mnt_stat.f_mntonname, MNAMELEN);
157 		memcpy(sbp->f_mntfromname, mp->mnt_stat.f_mntfromname,
158 		    MNAMELEN);
159 	}
160 	nfsm_reqdone;
161 	nfs_nput(vp);
162 	crfree(cred);
163 	return (error);
164 }
165 
166 /*
167  * Mount a remote root fs via. nfs. This depends on the info in the
168  * nfs_diskless structure that has been filled in properly by some primary
169  * bootstrap.
170  * It goes something like this:
171  * - do enough of "ifconfig" by calling ifioctl() so that the system
172  *   can talk to the server
173  * - If nfs_diskless.mygateway is filled in, use that address as
174  *   a default gateway.
175  *   (This is done the 4.3 way with rtioctl() and should be changed)
176  * - hand craft the swap nfs vnode hanging off a fake mount point
177  * - build the rootfs mount point and call mountnfs() to do the rest.
178  */
nfs_mountroot()179 nfs_mountroot()
180 {
181 	register struct mount *mp;
182 	register struct mbuf *m;
183 	struct socket *so;
184 	struct vnode *vp;
185 	int error;
186 
187 	/*
188 	 * Do enough of ifconfig(8) so that critical net interface can
189 	 * talk to the server.
190 	 */
191 	if (socreate(nfs_diskless.myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0))
192 		panic("nfs ifconf");
193 	if (ifioctl(so, SIOCAIFADDR, (caddr_t)&nfs_diskless.myif, curproc))
194 		panic("nfs ifconf2");
195 	soclose(so);
196 
197 	/*
198 	 * If the gateway field is filled in, set it as the default route.
199 	 */
200 #ifdef COMPAT_43
201 	if (nfs_diskless.mygateway.sa_family == AF_INET) {
202 		struct ortentry rt;
203 		struct sockaddr_in *sin;
204 
205 		sin = (struct sockaddr_in *) &rt.rt_dst;
206 		sin->sin_len = sizeof (struct sockaddr_in);
207 		sin->sin_family = AF_INET;
208 		sin->sin_addr.s_addr = 0;	/* default */
209 		memcpy((caddr_t)&rt.rt_gateway, (caddr_t)&nfs_diskless.mygateway,
210 			sizeof (struct sockaddr_in));
211 		rt.rt_flags = (RTF_UP | RTF_GATEWAY);
212 		if (RTIOCTL(SIOCADDRT, (caddr_t)&rt, curproc))
213 			panic("nfs root route");
214 	}
215 #endif	/* COMPAT_43 */
216 
217 #ifdef not_quite_right
218 Handle swapping after mount of root, during rc after mount of all fs.
219 Allow addswap to swap to an ordinary vnode (which may be on another fs).
220 	/*
221 	 * If swapping to an nfs node (indicated by swdevt[0].sw_dev == BLK_NODEV):
222 	 * Create a fake mount point just for the swap vnode so that the
223 	 * swap file can be on a different server from the rootfs.
224 	 */
225 	if (swdevt[0].sw_dev == BLK_NODEV) {
226 		mp = (struct mount *)malloc((u_long)sizeof(struct mount),
227 			M_MOUNT, M_NOWAIT);
228 		if (mp == NULL)
229 			panic("nfs root mount");
230 		mp->mnt_op = &nfs_vfsops;
231 		mp->mnt_flag = 0;
232 		mp->mnt_exroot = 0;
233 		mp->mnt_mounth = NULLVP;
234 
235 		/*
236 		 * Set up the diskless nfs_args for the swap mount point
237 		 * and then call mountnfs() to mount it.
238 		 * Since the swap file is not the root dir of a file system,
239 		 * hack it to a regular file.
240 		 */
241 		nfs_diskless.swap_args.fh = (nfsv2fh_t *)nfs_diskless.swap_fh;
242 		MGET(m, MT_SONAME, M_DONTWAIT);
243 		if (m == NULL)
244 			panic("nfs root mbuf");
245 		memcpy(mtod(m, caddr_t), (caddr_t)&nfs_diskless.swap_saddr,
246 			nfs_diskless.swap_saddr.sa_len);
247 		m->m_len = nfs_diskless.swap_saddr.sa_len;
248 		if (mountnfs(&nfs_diskless.swap_args, mp, m, "/swap",
249 			nfs_diskless.swap_hostnam, &vp))
250 			panic("nfs swap");
251 		vp->v_type = VREG;
252 		vp->v_flag = 0;
253 		swapdev_vp = vp;
254 		VREF(vp);
255 		swdevt[0].sw_vp = vp;
256 	}
257 #endif
258 
259 	/*
260 	 * Create the rootfs mount point.
261 	 */
262 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
263 		M_MOUNT, M_NOWAIT);
264 	if (mp == NULL)
265 		panic("nfs root mount2");
266 	mp->mnt_op = &nfs_vfsops;
267 	mp->mnt_flag = MNT_RDONLY;
268 	mp->mnt_exroot = 0;
269 	mp->mnt_mounth = NULLVP;
270 
271 	/*
272 	 * Set up the root fs args and call mountnfs() to do the rest.
273 	 */
274 	nfs_diskless.root_args.fh = (nfsv2fh_t *)nfs_diskless.root_fh;
275 	MGET(m, MT_SONAME, M_DONTWAIT);
276 	if (m == NULL)
277 		panic("nfs root mbuf2");
278 	memcpy(mtod(m, caddr_t), (caddr_t)&nfs_diskless.root_saddr,
279 		nfs_diskless.root_saddr.sa_len);
280 	m->m_len = nfs_diskless.root_saddr.sa_len;
281 	if (mountnfs(&nfs_diskless.root_args, mp, m, "/",
282 		nfs_diskless.root_hostnam, &vp))
283 		panic("nfs root");
284 	if (vfs_lock(mp))
285 		panic("nfs root2");
286 	rootfs = mp;
287 	mp->mnt_next = mp;
288 	mp->mnt_prev = mp;
289 	mp->mnt_vnodecovered = NULLVP;
290 	vfs_unlock(mp);
291 	rootvp = vp;
292 	inittodr((time_t)0);	/* There is no time in the nfs fsstat so ?? */
293 	return (0);
294 }
295 
296 /*
297  * VFS Operations.
298  *
299  * mount system call
300  * It seems a bit dumb to copyinstr() the host and path here and then
301  * memcpy() them in mountnfs(), but I wanted to detect errors before
302  * doing the sockargs() call because sockargs() allocates an mbuf and
303  * an error after that means that I have to release the mbuf.
304  */
305 /* ARGSUSED */
306 nfs_mount(mp, path, data, ndp, p)
307 	struct mount *mp;
308 	char *path;
309 	caddr_t data;
310 	struct nameidata *ndp;
311 	struct proc *p;
312 {
313 	int error;
314 	struct nfs_args args;
315 	struct mbuf *nam;
316 	struct vnode *vp;
317 	char pth[MNAMELEN], hst[MNAMELEN];
318 	u_int len;
319 	nfsv2fh_t nfh;
320 
321 	if (mp->mnt_flag & MNT_UPDATE)
322 		return (0);
323 	if (error = copyin(p, data, (caddr_t)&args, sizeof (struct nfs_args)))
324 		return (error);
325 	if (error = copyin(p, (caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t)))
326 		return (error);
327 	if (error = copyinstr(p, path, pth, MNAMELEN-1, &len))
328 		return (error);
329 	memset(&pth[len], 0, MNAMELEN - len);
330 	if (error = copyinstr(p, args.hostname, hst, MNAMELEN-1, &len))
331 		return (error);
332 	memset(&hst[len], 0, MNAMELEN - len);
333 	/* sockargs() call must be after above copyin() calls */
334 	if (error = sockargs(&nam, (caddr_t)args.addr,
335 		sizeof (struct sockaddr), MT_SONAME))
336 		return (error);
337 	args.fh = &nfh;
338 	error = mountnfs(&args, mp, nam, pth, hst, &vp);
339 	return (error);
340 }
341 
342 /*
343  * Common code for mount and mountroot
344  */
mountnfs(argp,mp,nam,pth,hst,vpp)345 mountnfs(argp, mp, nam, pth, hst, vpp)
346 	register struct nfs_args *argp;
347 	register struct mount *mp;
348 	struct mbuf *nam;
349 	char *pth, *hst;
350 	struct vnode **vpp;
351 {
352 	register struct nfsmount *nmp;
353 	struct proc *p = curproc;		/* XXX */
354 	struct nfsnode *np;
355 	int error;
356 	fsid_t tfsid;
357 
358 	MALLOC(nmp, struct nfsmount *, sizeof *nmp, M_NFSMNT, M_WAITOK);
359 	memset((caddr_t)nmp, 0, sizeof *nmp);
360 	mp->mnt_data = (qaddr_t)nmp;
361 	/*
362 	 * Generate a unique nfs mount id. The problem is that a dev number
363 	 * is not unique across multiple systems. The techique is as follows:
364 	 * 1) Set to nblkdev,0 which will never be used otherwise
365 	 * 2) Generate a first guess as nblkdev,nfs_mntid where nfs_mntid is
366 	 *	NOT 0
367 	 * 3) Loop searching the mount list for another one with same id
368 	 *	If a match, increment val[0] and try again
369 	 * NB: I increment val[0] { a long } instead of nfs_mntid { a u_char }
370 	 *	so that nfs is not limited to 255 mount points
371 	 *     Incrementing the high order bits does no real harm, since it
372 	 *     simply makes the major dev number tick up. The upper bound is
373 	 *     set to major dev 127 to avoid any sign extension problems
374 	 */
375 	mp->mnt_stat.f_fsid.val[0] = makedev(100, 0); /* XXX */
376 	/*mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev, 0);*/
377 	mp->mnt_stat.f_fsid.val[1] = MOUNT_NFS;
378 	if (++nfs_mntid == 0)
379 		++nfs_mntid;
380 	tfsid.val[0] = makedev(100, nfs_mntid); /* XXX */
381 	/*tfsid.val[0] = makedev(nblkdev, nfs_mntid);*/
382 	tfsid.val[1] = MOUNT_NFS;
383 	while (rootfs && getvfs(&tfsid)) {
384 		tfsid.val[0]++;
385 		nfs_mntid++;
386 	}
387 	if (major(tfsid.val[0]) > 127) {
388 		error = ENOENT;
389 		goto bad;
390 	}
391 	mp->mnt_stat.f_fsid.val[0] = tfsid.val[0];
392 	nmp->nm_mountp = mp;
393 	nmp->nm_flag = argp->flags;
394 	nmp->nm_rto = NFS_TIMEO;
395 	nmp->nm_rtt = -1;
396 	nmp->nm_rttvar = nmp->nm_rto << 1;
397 	nmp->nm_retry = NFS_RETRANS;
398 	nmp->nm_wsize = NFS_WSIZE;
399 	nmp->nm_rsize = NFS_RSIZE;
400 	memcpy((caddr_t)&nmp->nm_fh, (caddr_t)argp->fh, sizeof(nfsv2fh_t));
401 	memcpy(mp->mnt_stat.f_mntfromname, hst, MNAMELEN);
402 	memcpy(mp->mnt_stat.f_mntonname, pth, MNAMELEN);
403 	nmp->nm_nam = nam;
404 
405 	if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
406 		nmp->nm_rto = argp->timeo;
407 		/* NFS timeouts are specified in 1/10 sec. */
408 		nmp->nm_rto = (nmp->nm_rto * 10) / NFS_HZ;
409 		if (nmp->nm_rto < NFS_MINTIMEO)
410 			nmp->nm_rto = NFS_MINTIMEO;
411 		else if (nmp->nm_rto > NFS_MAXTIMEO)
412 			nmp->nm_rto = NFS_MAXTIMEO;
413 		nmp->nm_rttvar = nmp->nm_rto << 1;
414 	}
415 
416 	if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
417 		nmp->nm_retry = argp->retrans;
418 		if (nmp->nm_retry > NFS_MAXREXMIT)
419 			nmp->nm_retry = NFS_MAXREXMIT;
420 	}
421 
422 	if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
423 		nmp->nm_wsize = argp->wsize;
424 		/* Round down to multiple of blocksize */
425 		nmp->nm_wsize &= ~0x1ff;
426 		if (nmp->nm_wsize <= 0)
427 			nmp->nm_wsize = 512;
428 		else if (nmp->nm_wsize > NFS_MAXDATA)
429 			nmp->nm_wsize = NFS_MAXDATA;
430 	}
431 	if (nmp->nm_wsize > MAXBSIZE)
432 		nmp->nm_wsize = MAXBSIZE;
433 
434 	if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
435 		nmp->nm_rsize = argp->rsize;
436 		/* Round down to multiple of blocksize */
437 		nmp->nm_rsize &= ~0x1ff;
438 		if (nmp->nm_rsize <= 0)
439 			nmp->nm_rsize = 512;
440 		else if (nmp->nm_rsize > NFS_MAXDATA)
441 			nmp->nm_rsize = NFS_MAXDATA;
442 	}
443 	if (nmp->nm_rsize > MAXBSIZE)
444 		nmp->nm_rsize = MAXBSIZE;
445 	/* Set up the sockets and per-host congestion */
446 	nmp->nm_sotype = argp->sotype;
447 	nmp->nm_soproto = argp->proto;
448 	if (error = nfs_connect(nmp))
449 		goto bad;
450 
451 	if (error = nfs_statfs(mp, &mp->mnt_stat, p))
452 		goto bad;
453 	/*
454 	 * A reference count is needed on the nfsnode representing the
455 	 * remote root.  If this object is not persistent, then backward
456 	 * traversals of the mount point (i.e. "..") will not work if
457 	 * the nfsnode gets flushed out of the cache. Ufs does not have
458 	 * this problem, because one can identify root inodes by their
459 	 * number == ROOTINO (2).
460 	 */
461 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
462 		goto bad;
463 	/*
464 	 * Unlock it, but keep the reference count.
465 	 */
466 	nfs_unlock(NFSTOV(np));
467 	*vpp = NFSTOV(np);
468 
469 	return (0);
470 bad:
471 	nfs_disconnect(nmp);
472 	FREE(nmp, M_NFSMNT);
473 	m_freem(nam);
474 	return (error);
475 }
476 
477 /*
478  * unmount system call
479  */
480 nfs_unmount(mp, mntflags, p)
481 	struct mount *mp;
482 	int mntflags;
483 	struct proc *p;
484 {
485 	register struct nfsmount *nmp;
486 	struct nfsnode *np;
487 	struct vnode *vp;
488 	int error, flags = 0;
489 
490 	if (mntflags & MNT_FORCE) {
491 		if (mp == rootfs)
492 			return (EINVAL);
493 		flags |= FORCECLOSE;
494 	}
495 	nmp = VFSTONFS(mp);
496 	/*
497 	 * Clear out the buffer cache
498 	 */
499 	mntflushbuf(mp, 0);
500 	if (mntinvalbuf(mp))
501 		return (EBUSY);
502 	/*
503 	 * Goes something like this..
504 	 * - Check for activity on the root vnode (other than ourselves).
505 	 * - Call vflush() to clear out vnodes for this file system,
506 	 *   except for the root vnode.
507 	 * - Decrement reference on the vnode representing remote root.
508 	 * - Close the socket
509 	 * - Free up the data structures
510 	 */
511 	/*
512 	 * We need to decrement the ref. count on the nfsnode representing
513 	 * the remote root.  See comment in mountnfs().  The VFS unmount()
514 	 * has done vput on this vnode, otherwise we would get deadlock!
515 	 */
516 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
517 		return(error);
518 	vp = NFSTOV(np);
519 	if (vp->v_usecount > 2) {
520 		vput(vp);
521 		return (EBUSY);
522 	}
523 	if (error = vflush(mp, vp, flags)) {
524 		vput(vp);
525 		return (error);
526 	}
527 	/*
528 	 * Get rid of two reference counts, and unlock it on the second.
529 	 */
530 	vrele(vp);
531 	vput(vp);
532 	nfs_disconnect(nmp);
533 	m_freem(nmp->nm_nam);
534 	free((caddr_t)nmp, M_NFSMNT);
535 	return (0);
536 }
537 
538 /*
539  * Return root of a filesystem
540  */
541 nfs_root(mp, vpp)
542 	struct mount *mp;
543 	struct vnode **vpp;
544 {
545 	register struct vnode *vp;
546 	struct nfsmount *nmp;
547 	struct nfsnode *np;
548 	int error;
549 
550 	nmp = VFSTONFS(mp);
551 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
552 		return (error);
553 	vp = NFSTOV(np);
554 	vp->v_type = VDIR;
555 	vp->v_flag = VROOT;
556 	*vpp = vp;
557 	return (0);
558 }
559 
560 extern int syncprt;
561 
562 /*
563  * Flush out the buffer cache
564  */
565 /* ARGSUSED */
566 nfs_sync(mp, waitfor)
567 	struct mount *mp;
568 	int waitfor;
569 {
570 	/* if (syncprt)
571 		bufstats(); */
572 	/*
573 	 * Force stale buffer cache information to be flushed.
574 	 */
575 	mntflushbuf(mp, waitfor == MNT_WAIT ? B_SYNC : 0);
576 	return (0);
577 }
578 
579 /*
580  * At this point, this should never happen
581  */
582 /* ARGSUSED */
583 nfs_fhtovp(mp, fhp, vpp)
584 	struct mount *mp;
585 	struct fid *fhp;
586 	struct vnode **vpp;
587 {
588 
589 	return (EINVAL);
590 }
591 
592 /*
593  * Vnode pointer to File handle, should never happen either
594  */
595 /* ARGSUSED */
596 nfs_vptofh(vp, fhp)
597 	struct vnode *vp;
598 	struct fid *fhp;
599 {
600 
601 	return (EINVAL);
602 }
603 
604 /*
605  * Vfs start routine, a no-op.
606  */
607 /* ARGSUSED */
608 nfs_start(mp, flags, p)
609 	struct mount *mp;
610 	int flags;
611 	struct proc *p;
612 {
613 
614 	return (0);
615 }
616 
617 /*
618  * Do operations associated with quotas, not supported
619  */
620 int
nfs_quotactl(struct mount * mp,int cmd,uid_t uid,caddr_t arg,struct proc * p)621 nfs_quotactl(struct mount *mp, int cmd, uid_t uid, caddr_t arg, struct proc *p)
622 {
623 #ifdef lint
624 	mp = mp; cmd = cmd; uid = uid; arg = arg;
625 #endif /* lint */
626 	return (EOPNOTSUPP);
627 }
628