2 * Copyright (c) 1989, 1993, 1995
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
36 * @(#)nfs_vfsops.c 8.12 (Berkeley) 5/20/95
37 * $Id: nfs_vfsops.c,v 1.43 1997/06/03 17:22:47 dfr Exp $
40 #include <sys/param.h>
42 #include <sys/sockio.h>
43 #include <sys/signal.h>
45 #include <sys/namei.h>
46 #include <sys/vnode.h>
47 #include <sys/kernel.h>
48 #include <sys/sysctl.h>
49 #include <sys/mount.h>
52 #include <sys/socket.h>
53 #include <sys/socketvar.h>
54 #include <sys/systm.h>
57 #include <vm/vm_param.h>
58 #include <vm/vm_extern.h>
61 #include <net/route.h>
62 #include <netinet/in.h>
64 #include <nfs/rpcv2.h>
65 #include <nfs/nfsproto.h>
66 #include <nfs/nfsnode.h>
68 #include <nfs/nfsmount.h>
69 #include <nfs/xdr_subs.h>
70 #include <nfs/nfsm_subs.h>
71 #include <nfs/nfsdiskless.h>
72 #include <nfs/nqnfs.h>
74 extern int nfs_mountroot __P((struct mount *mp));
78 struct nfsstats nfsstats;
79 SYSCTL_NODE(_vfs, MOUNT_NFS, nfs, CTLFLAG_RW, 0, "NFS filesystem");
80 SYSCTL_STRUCT(_vfs_nfs, NFS_NFSSTATS, nfsstats, CTLFLAG_RD,
81 &nfsstats, nfsstats, "");
84 SYSCTL_INT(_vfs_nfs, OID_AUTO, debug, CTLFLAG_RW, &nfs_debug, 0, "");
87 static int nfs_iosize __P((struct nfsmount *nmp));
88 static int mountnfs __P((struct nfs_args *,struct mount *,
89 struct mbuf *,char *,char *,struct vnode **));
90 static int nfs_mount __P(( struct mount *mp, char *path, caddr_t data,
91 struct nameidata *ndp, struct proc *p));
92 static int nfs_start __P(( struct mount *mp, int flags,
94 static int nfs_unmount __P(( struct mount *mp, int mntflags,
96 static int nfs_root __P(( struct mount *mp, struct vnode **vpp));
97 static int nfs_quotactl __P(( struct mount *mp, int cmds, uid_t uid,
98 caddr_t arg, struct proc *p));
99 static int nfs_statfs __P(( struct mount *mp, struct statfs *sbp,
101 static int nfs_sync __P(( struct mount *mp, int waitfor,
102 struct ucred *cred, struct proc *p));
103 static int nfs_vptofh __P(( struct vnode *vp, struct fid *fhp));
104 static int nfs_fhtovp __P((struct mount *mp, struct fid *fhp,
105 struct mbuf *nam, struct vnode **vpp,
106 int *exflagsp, struct ucred **credanonp));
107 static int nfs_vget __P((struct mount *, ino_t, struct vnode **));
111 * nfs vfs operations.
113 static struct vfsops nfs_vfsops = {
126 VFS_SET(nfs_vfsops, nfs, MOUNT_NFS, VFCF_NETWORK);
129 * This structure must be filled in by a primary bootstrap or bootstrap
130 * server for a diskless/dataless machine. It is initialized below just
131 * to ensure that it is allocated to initialized data (.data not .bss).
133 struct nfs_diskless nfs_diskless = { 0 };
134 struct nfsv3_diskless nfsv3_diskless = { 0 };
135 int nfs_diskless_valid = 0;
137 SYSCTL_INT(_vfs_nfs, OID_AUTO, diskless_valid, CTLFLAG_RD,
138 &nfs_diskless_valid, 0, "");
140 SYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD,
141 nfsv3_diskless.root_hostnam, 0, "");
143 SYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD,
144 &nfsv3_diskless.root_saddr, sizeof nfsv3_diskless.root_saddr,
145 "%Ssockaddr_in", "");
147 SYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_swappath, CTLFLAG_RD,
148 nfsv3_diskless.swap_hostnam, 0, "");
150 SYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_swapaddr, CTLFLAG_RD,
151 &nfsv3_diskless.swap_saddr, sizeof nfsv3_diskless.swap_saddr,
155 void nfsargs_ntoh __P((struct nfs_args *));
156 static int nfs_mountdiskless __P((char *, char *, int,
157 struct sockaddr_in *, struct nfs_args *,
158 struct proc *, struct vnode **,
160 void nfs_convert_diskless __P((void));
161 static void nfs_convert_oargs __P((struct nfs_args *args,
162 struct onfs_args *oargs));
164 static int nfs_iosize(nmp)
165 struct nfsmount* nmp;
170 * Calculate the size used for io buffers. Use the larger
171 * of the two sizes to minimise nfs requests but make sure
172 * that it is at least one VM page to avoid wasting buffer
175 iosize = max(nmp->nm_rsize, nmp->nm_wsize);
176 if (iosize < PAGE_SIZE) iosize = PAGE_SIZE;
180 static void nfs_convert_oargs(args,oargs)
181 struct nfs_args *args;
182 struct onfs_args *oargs;
184 args->version = NFS_ARGSVERSION;
185 args->addr = oargs->addr;
186 args->addrlen = oargs->addrlen;
187 args->sotype = oargs->sotype;
188 args->proto = oargs->proto;
189 args->fh = oargs->fh;
190 args->fhsize = oargs->fhsize;
191 args->flags = oargs->flags;
192 args->wsize = oargs->wsize;
193 args->rsize = oargs->rsize;
194 args->readdirsize = oargs->readdirsize;
195 args->timeo = oargs->timeo;
196 args->retrans = oargs->retrans;
197 args->maxgrouplist = oargs->maxgrouplist;
198 args->readahead = oargs->readahead;
199 args->leaseterm = oargs->leaseterm;
200 args->deadthresh = oargs->deadthresh;
201 args->hostname = oargs->hostname;
204 void nfs_convert_diskless()
206 bcopy(&nfs_diskless.myif, &nfsv3_diskless.myif,
207 sizeof(struct ifaliasreq));
208 bcopy(&nfs_diskless.mygateway, &nfsv3_diskless.mygateway,
209 sizeof(struct sockaddr_in));
210 nfs_convert_oargs(&nfsv3_diskless.swap_args,&nfs_diskless.swap_args);
211 nfsv3_diskless.swap_fhsize = NFSX_V2FH;
212 bcopy(nfs_diskless.swap_fh,nfsv3_diskless.swap_fh,NFSX_V2FH);
213 bcopy(&nfs_diskless.swap_saddr,&nfsv3_diskless.swap_saddr,
214 sizeof(struct sockaddr_in));
215 bcopy(nfs_diskless.swap_hostnam,nfsv3_diskless.swap_hostnam,
217 nfsv3_diskless.swap_nblks = nfs_diskless.swap_nblks;
218 bcopy(&nfs_diskless.swap_ucred, &nfsv3_diskless.swap_ucred,
219 sizeof(struct ucred));
220 nfs_convert_oargs(&nfsv3_diskless.root_args,&nfs_diskless.root_args);
221 nfsv3_diskless.root_fhsize = NFSX_V2FH;
222 bcopy(nfs_diskless.root_fh,nfsv3_diskless.root_fh,NFSX_V2FH);
223 bcopy(&nfs_diskless.root_saddr,&nfsv3_diskless.root_saddr,
224 sizeof(struct sockaddr_in));
225 bcopy(nfs_diskless.root_hostnam,nfsv3_diskless.root_hostnam,
227 nfsv3_diskless.root_time = nfs_diskless.root_time;
228 bcopy(nfs_diskless.my_hostnam,nfsv3_diskless.my_hostnam,
230 nfs_diskless_valid = 3;
237 nfs_statfs(mp, sbp, p)
239 register struct statfs *sbp;
242 register struct vnode *vp;
243 register struct nfs_statfs *sfp;
246 register long t1, t2;
247 caddr_t bpos, dpos, cp2;
248 struct nfsmount *nmp = VFSTONFS(mp);
249 int error = 0, v3 = (nmp->nm_flag & NFSMNT_NFSV3), retattr;
250 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
256 sfp = (struct nfs_statfs *)0;
258 error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
263 cred->cr_ngroups = 1;
264 if (v3 && (nmp->nm_flag & NFSMNT_GOTFSINFO) == 0)
265 (void)nfs_fsinfo(nmp, vp, cred, p);
266 nfsstats.rpccnt[NFSPROC_FSSTAT]++;
267 nfsm_reqhead(vp, NFSPROC_FSSTAT, NFSX_FH(v3));
269 nfsm_request(vp, NFSPROC_FSSTAT, p, cred);
271 nfsm_postop_attr(vp, retattr);
273 nfsm_dissect(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
284 sbp->f_type = MOUNT_NFS;
286 sbp->f_flags = nmp->nm_flag;
287 sbp->f_iosize = nfs_iosize(nmp);
289 sbp->f_bsize = NFS_FABLKSIZE;
290 fxdr_hyper(&sfp->sf_tbytes, &tquad);
291 sbp->f_blocks = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE));
292 fxdr_hyper(&sfp->sf_fbytes, &tquad);
293 sbp->f_bfree = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE));
294 fxdr_hyper(&sfp->sf_abytes, &tquad);
295 sbp->f_bavail = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE));
296 sbp->f_files = (fxdr_unsigned(long, sfp->sf_tfiles.nfsuquad[1])
298 sbp->f_ffree = (fxdr_unsigned(long, sfp->sf_ffiles.nfsuquad[1])
301 sbp->f_bsize = fxdr_unsigned(long, sfp->sf_bsize);
302 sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks);
303 sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree);
304 sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail);
308 if (sbp != &mp->mnt_stat) {
309 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
310 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
319 * nfs version 3 fsinfo rpc call
322 nfs_fsinfo(nmp, vp, cred, p)
323 register struct nfsmount *nmp;
324 register struct vnode *vp;
328 register struct nfsv3_fsinfo *fsp;
330 register long t1, t2;
331 register u_long *tl, pref, max;
332 caddr_t bpos, dpos, cp2;
333 int error = 0, retattr;
334 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
336 nfsstats.rpccnt[NFSPROC_FSINFO]++;
337 nfsm_reqhead(vp, NFSPROC_FSINFO, NFSX_FH(1));
339 nfsm_request(vp, NFSPROC_FSINFO, p, cred);
340 nfsm_postop_attr(vp, retattr);
342 nfsm_dissect(fsp, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
343 pref = fxdr_unsigned(u_long, fsp->fs_wtpref);
344 if (pref < nmp->nm_wsize)
345 nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) &
346 ~(NFS_FABLKSIZE - 1);
347 max = fxdr_unsigned(u_long, fsp->fs_wtmax);
348 if (max < nmp->nm_wsize) {
349 nmp->nm_wsize = max & ~(NFS_FABLKSIZE - 1);
350 if (nmp->nm_wsize == 0)
353 pref = fxdr_unsigned(u_long, fsp->fs_rtpref);
354 if (pref < nmp->nm_rsize)
355 nmp->nm_rsize = (pref + NFS_FABLKSIZE - 1) &
356 ~(NFS_FABLKSIZE - 1);
357 max = fxdr_unsigned(u_long, fsp->fs_rtmax);
358 if (max < nmp->nm_rsize) {
359 nmp->nm_rsize = max & ~(NFS_FABLKSIZE - 1);
360 if (nmp->nm_rsize == 0)
363 pref = fxdr_unsigned(u_long, fsp->fs_dtpref);
364 if (pref < nmp->nm_readdirsize)
365 nmp->nm_readdirsize = pref;
366 if (max < nmp->nm_readdirsize) {
367 nmp->nm_readdirsize = max;
369 nmp->nm_flag |= NFSMNT_GOTFSINFO;
376 * Mount a remote root fs via. nfs. This depends on the info in the
377 * nfs_diskless structure that has been filled in properly by some primary
379 * It goes something like this:
380 * - do enough of "ifconfig" by calling ifioctl() so that the system
381 * can talk to the server
382 * - If nfs_diskless.mygateway is filled in, use that address as
384 * - hand craft the swap nfs vnode hanging off a fake mount point
385 * if swdevt[0].sw_dev == NODEV
386 * - build the rootfs mount point and call mountnfs() to do the rest.
392 struct mount *swap_mp;
393 struct nfsv3_diskless *nd = &nfsv3_diskless;
396 struct proc *p = curproc; /* XXX */
402 * XXX time must be non-zero when we init the interface or else
403 * the arp code will wedge...
405 if (time.tv_sec == 0)
408 if (nfs_diskless_valid==1)
409 nfs_convert_diskless();
412 * XXX splnet, so networks will receive...
417 /* Set up swap credentials. */
418 proc0.p_ucred->cr_uid = ntohl(nd->swap_ucred.cr_uid);
419 proc0.p_ucred->cr_gid = ntohl(nd->swap_ucred.cr_gid);
420 if ((proc0.p_ucred->cr_ngroups = ntohs(nd->swap_ucred.cr_ngroups)) >
422 proc0.p_ucred->cr_ngroups = NGROUPS;
423 for (i = 0; i < proc0.p_ucred->cr_ngroups; i++)
424 proc0.p_ucred->cr_groups[i] = ntohl(nd->swap_ucred.cr_groups[i]);
428 * Do enough of ifconfig(8) so that the critical net interface can
429 * talk to the server.
431 error = socreate(nd->myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0, p);
433 panic("nfs_mountroot: socreate(%04x): %d",
434 nd->myif.ifra_addr.sa_family, error);
437 * We might not have been told the right interface, so we pass
438 * over the first ten interfaces of the same kind, until we get
439 * one of them configured.
442 for (i = strlen(nd->myif.ifra_name) - 1;
443 nd->myif.ifra_name[i] >= '0' &&
444 nd->myif.ifra_name[i] <= '9';
445 nd->myif.ifra_name[i] ++) {
446 error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, p);
451 panic("nfs_mountroot: SIOCAIFADDR: %d", error);
455 * If the gateway field is filled in, set it as the default route.
457 if (nd->mygateway.sin_len != 0) {
458 struct sockaddr_in mask, sin;
460 bzero((caddr_t)&mask, sizeof(mask));
462 sin.sin_family = AF_INET;
463 sin.sin_len = sizeof(sin);
464 error = rtrequest(RTM_ADD, (struct sockaddr *)&sin,
465 (struct sockaddr *)&nd->mygateway,
466 (struct sockaddr *)&mask,
467 RTF_UP | RTF_GATEWAY, (struct rtentry **)0);
469 panic("nfs_mountroot: RTM_ADD: %d", error);
473 * Create the rootfs mount point.
475 nd->root_args.fh = nd->root_fh;
476 nd->root_args.fhsize = nd->root_fhsize;
477 l = ntohl(nd->root_saddr.sin_addr.s_addr);
478 sprintf(buf,"%ld.%ld.%ld.%ld:%s",
479 (l >> 24) & 0xff, (l >> 16) & 0xff,
480 (l >> 8) & 0xff, (l >> 0) & 0xff,nd->root_hostnam);
481 printf("NFS ROOT: %s\n",buf);
482 if (error = nfs_mountdiskless(buf, "/", MNT_RDONLY,
483 &nd->root_saddr, &nd->root_args, p, &vp, &mp)) {
485 mp->mnt_vfc->vfc_refcount--;
486 free(swap_mp, M_MOUNT);
492 if (nd->swap_nblks) {
494 /* Convert to DEV_BSIZE instead of Kilobyte */
498 * Create a fake mount point just for the swap vnode so that the
499 * swap file can be on a different server from the rootfs.
501 nd->swap_args.fh = nd->swap_fh;
502 nd->swap_args.fhsize = nd->swap_fhsize;
503 l = ntohl(nd->swap_saddr.sin_addr.s_addr);
504 sprintf(buf,"%ld.%ld.%ld.%ld:%s",
505 (l >> 24) & 0xff, (l >> 16) & 0xff,
506 (l >> 8) & 0xff, (l >> 0) & 0xff,nd->swap_hostnam);
507 printf("NFS SWAP: %s\n",buf);
508 if (error = nfs_mountdiskless(buf, "/swap", 0,
509 &nd->swap_saddr, &nd->swap_args, p, &vp, &swap_mp))
511 vfs_unbusy(swap_mp, p);
513 VTONFS(vp)->n_size = VTONFS(vp)->n_vattr.va_size =
514 nd->swap_nblks * DEV_BSIZE ;
517 * Since the swap file is not the root dir of a file system,
518 * hack it to a regular file.
523 swaponvp(p, vp, NODEV, nd->swap_nblks);
526 mp->mnt_flag |= MNT_ROOTFS;
527 mp->mnt_vnodecovered = NULLVP;
532 * This is not really an nfs issue, but it is much easier to
533 * set hostname here and then let the "/etc/rc.xxx" files
534 * mount the right /var based upon its preset value.
536 bcopy(nd->my_hostnam, hostname, MAXHOSTNAMELEN);
537 hostname[MAXHOSTNAMELEN - 1] = '\0';
538 for (i = 0; i < MAXHOSTNAMELEN; i++)
539 if (hostname[i] == '\0')
541 inittodr(ntohl(nd->root_time));
546 * Internal version of mount system call for diskless setup.
549 nfs_mountdiskless(path, which, mountflag, sin, args, p, vpp, mpp)
553 struct sockaddr_in *sin;
554 struct nfs_args *args;
565 if (!mp && ( error = vfs_rootmountalloc("nfs", path, &mp))) {
566 printf("nfs_mountroot: NFS not configured");
570 mp->mnt_flag = mountflag;
571 MGET(m, MT_SONAME, M_WAITOK);
572 bcopy((caddr_t)sin, mtod(m, caddr_t), sin->sin_len);
573 m->m_len = sin->sin_len;
574 if (error = mountnfs(args, mp, m, which, path, vpp)) {
575 printf("nfs_mountroot: mount %s on %s: %d", path, which, error);
576 mp->mnt_vfc->vfc_refcount--;
581 (void) copystr(which, mp->mnt_stat.f_mntonname, MNAMELEN - 1, 0);
590 * It seems a bit dumb to copyinstr() the host and path here and then
591 * bcopy() them in mountnfs(), but I wanted to detect errors before
592 * doing the sockargs() call because sockargs() allocates an mbuf and
593 * an error after that means that I have to release the mbuf.
597 nfs_mount(mp, path, data, ndp, p)
601 struct nameidata *ndp;
605 struct nfs_args args;
608 char pth[MNAMELEN], hst[MNAMELEN];
610 u_char nfh[NFSX_V3FHMAX];
616 error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args));
619 if (args.version != NFS_ARGSVERSION) {
620 #ifndef NO_COMPAT_PRELITE2
622 * If the argument version is unknown, then assume the
623 * caller is a pre-lite2 4.4BSD client and convert its
626 struct onfs_args oargs;
627 error = copyin(data, (caddr_t)&oargs, sizeof (struct onfs_args));
630 nfs_convert_oargs(&args,&oargs);
631 #else /* NO_COMPAT_PRELITE2 */
632 return (EPROGMISMATCH);
633 #endif /* !NO_COMPAT_PRELITE2 */
635 error = copyin((caddr_t)args.fh, (caddr_t)nfh, args.fhsize);
638 error = copyinstr(path, pth, MNAMELEN-1, &len);
641 bzero(&pth[len], MNAMELEN - len);
642 error = copyinstr(args.hostname, hst, MNAMELEN-1, &len);
645 bzero(&hst[len], MNAMELEN - len);
646 /* sockargs() call must be after above copyin() calls */
647 error = sockargs(&nam, (caddr_t)args.addr, args.addrlen, MT_SONAME);
651 error = mountnfs(&args, mp, nam, pth, hst, &vp);
656 * Common code for mount and mountroot
659 mountnfs(argp, mp, nam, pth, hst, vpp)
660 register struct nfs_args *argp;
661 register struct mount *mp;
666 register struct nfsmount *nmp;
671 if (mp->mnt_flag & MNT_UPDATE) {
673 /* update paths, file handles, etc, here XXX */
677 MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount),
679 bzero((caddr_t)nmp, sizeof (struct nfsmount));
680 TAILQ_INIT(&nmp->nm_uidlruhead);
681 TAILQ_INIT(&nmp->nm_bufq);
682 mp->mnt_data = (qaddr_t)nmp;
686 nmp->nm_flag = argp->flags;
687 if (nmp->nm_flag & NFSMNT_NQNFS)
689 * We have to set mnt_maxsymlink to a non-zero value so
690 * that COMPAT_43 routines will know that we are setting
691 * the d_type field in directories (and can zero it for
692 * unsuspecting binaries).
694 mp->mnt_maxsymlinklen = 1;
695 nmp->nm_timeo = NFS_TIMEO;
696 nmp->nm_retry = NFS_RETRANS;
697 nmp->nm_wsize = NFS_WSIZE;
698 nmp->nm_rsize = NFS_RSIZE;
699 nmp->nm_readdirsize = NFS_READDIRSIZE;
700 nmp->nm_numgrps = NFS_MAXGRPS;
701 nmp->nm_readahead = NFS_DEFRAHEAD;
702 nmp->nm_leaseterm = NQ_DEFLEASE;
703 nmp->nm_deadthresh = NQ_DEADTHRESH;
704 CIRCLEQ_INIT(&nmp->nm_timerhead);
705 nmp->nm_inprog = NULLVP;
706 nmp->nm_fhsize = argp->fhsize;
707 bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize);
708 bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
709 bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN);
713 * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes
714 * no sense in that context.
716 if (argp->sotype == SOCK_STREAM)
717 argp->flags &= ~NFSMNT_NOCONN;
719 if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
720 nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
721 if (nmp->nm_timeo < NFS_MINTIMEO)
722 nmp->nm_timeo = NFS_MINTIMEO;
723 else if (nmp->nm_timeo > NFS_MAXTIMEO)
724 nmp->nm_timeo = NFS_MAXTIMEO;
727 if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
728 nmp->nm_retry = argp->retrans;
729 if (nmp->nm_retry > NFS_MAXREXMIT)
730 nmp->nm_retry = NFS_MAXREXMIT;
733 if (argp->flags & NFSMNT_NFSV3) {
734 if (argp->sotype == SOCK_DGRAM)
735 maxio = NFS_MAXDGRAMDATA;
739 maxio = NFS_V2MAXDATA;
741 if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
742 nmp->nm_wsize = argp->wsize;
743 /* Round down to multiple of blocksize */
744 nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1);
745 if (nmp->nm_wsize <= 0)
746 nmp->nm_wsize = NFS_FABLKSIZE;
748 if (nmp->nm_wsize > maxio)
749 nmp->nm_wsize = maxio;
750 if (nmp->nm_wsize > MAXBSIZE)
751 nmp->nm_wsize = MAXBSIZE;
753 if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
754 nmp->nm_rsize = argp->rsize;
755 /* Round down to multiple of blocksize */
756 nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1);
757 if (nmp->nm_rsize <= 0)
758 nmp->nm_rsize = NFS_FABLKSIZE;
760 if (nmp->nm_rsize > maxio)
761 nmp->nm_rsize = maxio;
762 if (nmp->nm_rsize > MAXBSIZE)
763 nmp->nm_rsize = MAXBSIZE;
765 if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) {
766 nmp->nm_readdirsize = argp->readdirsize;
768 if (nmp->nm_readdirsize > maxio)
769 nmp->nm_readdirsize = maxio;
770 if (nmp->nm_readdirsize > nmp->nm_rsize)
771 nmp->nm_readdirsize = nmp->nm_rsize;
773 if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 &&
774 argp->maxgrouplist <= NFS_MAXGRPS)
775 nmp->nm_numgrps = argp->maxgrouplist;
776 if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 &&
777 argp->readahead <= NFS_MAXRAHEAD)
778 nmp->nm_readahead = argp->readahead;
779 if ((argp->flags & NFSMNT_LEASETERM) && argp->leaseterm >= 2 &&
780 argp->leaseterm <= NQ_MAXLEASE)
781 nmp->nm_leaseterm = argp->leaseterm;
782 if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1 &&
783 argp->deadthresh <= NQ_NEVERDEAD)
784 nmp->nm_deadthresh = argp->deadthresh;
785 /* Set up the sockets and per-host congestion */
786 nmp->nm_sotype = argp->sotype;
787 nmp->nm_soproto = argp->proto;
790 * For Connection based sockets (TCP,...) defer the connect until
791 * the first request, in case the server is not responding.
793 if (nmp->nm_sotype == SOCK_DGRAM &&
794 (error = nfs_connect(nmp, (struct nfsreq *)0)))
798 * This is silly, but it has to be set so that vinifod() works.
799 * We do not want to do an nfs_statfs() here since we can get
800 * stuck on a dead server and we are holding a lock on the mount
803 mp->mnt_stat.f_iosize = nfs_iosize(nmp);
805 * A reference count is needed on the nfsnode representing the
806 * remote root. If this object is not persistent, then backward
807 * traversals of the mount point (i.e. "..") will not work if
808 * the nfsnode gets flushed out of the cache. Ufs does not have
809 * this problem, because one can identify root inodes by their
810 * number == ROOTINO (2).
812 error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
818 * Get file attributes for the mountpoint. This has the side
819 * effect of filling in (*vpp)->v_type with the correct value.
821 VOP_GETATTR(*vpp, &attrs, curproc->p_ucred, curproc);
824 * Lose the lock but keep the ref.
826 VOP_UNLOCK(*vpp, 0, curproc);
831 free((caddr_t)nmp, M_NFSMNT);
837 * unmount system call
840 nfs_unmount(mp, mntflags, p)
845 register struct nfsmount *nmp;
848 int error, flags = 0;
850 if (mntflags & MNT_FORCE)
854 * Goes something like this..
855 * - Check for activity on the root vnode (other than ourselves).
856 * - Call vflush() to clear out vnodes for this file system,
857 * except for the root vnode.
858 * - Decrement reference on the vnode representing remote root.
860 * - Free up the data structures
863 * We need to decrement the ref. count on the nfsnode representing
864 * the remote root. See comment in mountnfs(). The VFS unmount()
865 * has done vput on this vnode, otherwise we would get deadlock!
867 error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
871 if (vp->v_usecount > 2) {
877 * Must handshake with nqnfs_clientd() if it is active.
879 nmp->nm_flag |= NFSMNT_DISMINPROG;
880 while (nmp->nm_inprog != NULLVP)
881 (void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0);
882 error = vflush(mp, vp, flags);
885 nmp->nm_flag &= ~NFSMNT_DISMINPROG;
890 * We are now committed to the unmount.
891 * For NQNFS, let the server daemon free the nfsmount structure.
893 if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB))
894 nmp->nm_flag |= NFSMNT_DISMNT;
897 * There are two reference counts and one lock to get rid of here.
903 m_freem(nmp->nm_nam);
905 if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) == 0)
906 free((caddr_t)nmp, M_NFSMNT);
911 * Return root of a filesystem
918 register struct vnode *vp;
919 struct nfsmount *nmp;
924 error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
928 if (vp->v_type == VNON)
938 * Flush out the buffer cache
942 nfs_sync(mp, waitfor, cred, p)
948 register struct vnode *vp;
949 int error, allerror = 0;
952 * Force stale buffer cache information to be flushed.
955 for (vp = mp->mnt_vnodelist.lh_first;
957 vp = vp->v_mntvnodes.le_next) {
959 * If the vnode that we are about to sync is no longer
960 * associated with this mount point, start over.
962 if (vp->v_mount != mp)
964 if (VOP_ISLOCKED(vp) || vp->v_dirtyblkhd.lh_first == NULL)
966 if (vget(vp, LK_EXCLUSIVE, p))
968 error = VOP_FSYNC(vp, cred, waitfor, p);
977 * NFS flat namespace lookup.
978 * Currently unsupported.
982 nfs_vget(mp, ino, vpp)
992 * At this point, this should never happen
996 nfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
997 register struct mount *mp;
1002 struct ucred **credanonp;
1009 * Vnode pointer to File handle, should never happen either
1022 * Vfs start routine, a no-op.
1026 nfs_start(mp, flags, p)
1036 * Do operations associated with quotas, not supported
1040 nfs_quotactl(mp, cmd, uid, arg, p)
1048 return (EOPNOTSUPP);