Home | History | Annotate | Line # | Download | only in nfs
nfs_vfsops.c revision 1.1.1.3
      1 /*
      2  * Copyright (c) 1989, 1993, 1995
      3  *	The Regents of the University of California.  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  *	@(#)nfs_vfsops.c	8.12 (Berkeley) 5/20/95
     37  */
     38 
     39 #include <sys/param.h>
     40 #include <sys/conf.h>
     41 #include <sys/ioctl.h>
     42 #include <sys/signal.h>
     43 #include <sys/proc.h>
     44 #include <sys/namei.h>
     45 #include <sys/vnode.h>
     46 #include <sys/kernel.h>
     47 #include <sys/mount.h>
     48 #include <sys/buf.h>
     49 #include <sys/mbuf.h>
     50 #include <sys/socket.h>
     51 #include <sys/socketvar.h>
     52 #include <sys/systm.h>
     53 
     54 #include <net/if.h>
     55 #include <net/route.h>
     56 #include <netinet/in.h>
     57 
     58 #include <nfs/rpcv2.h>
     59 #include <nfs/nfsproto.h>
     60 #include <nfs/nfsnode.h>
     61 #include <nfs/nfs.h>
     62 #include <nfs/nfsmount.h>
     63 #include <nfs/xdr_subs.h>
     64 #include <nfs/nfsm_subs.h>
     65 #include <nfs/nfsdiskless.h>
     66 #include <nfs/nqnfs.h>
     67 
     68 struct nfsstats nfsstats;
     69 static int nfs_sysctl(int *, u_int, void *, size_t *, void *, size_t,
     70 		      struct proc *);
     71 extern int nfs_ticks;
     72 
     73 /*
     74  * nfs vfs operations.
     75  */
     76 struct vfsops nfs_vfsops = {
     77 	nfs_mount,
     78 	nfs_start,
     79 	nfs_unmount,
     80 	nfs_root,
     81 	nfs_quotactl,
     82 	nfs_statfs,
     83 	nfs_sync,
     84 	nfs_vget,
     85 	nfs_fhtovp,
     86 	nfs_vptofh,
     87 	nfs_init,
     88 	nfs_sysctl
     89 };
     90 
     91 /*
     92  * This structure must be filled in by a primary bootstrap or bootstrap
     93  * server for a diskless/dataless machine. It is initialized below just
     94  * to ensure that it is allocated to initialized data (.data not .bss).
     95  */
     96 struct nfs_diskless nfs_diskless = { 0 };
     97 int nfs_diskless_valid = 0;
     98 
     99 void nfs_disconnect __P((struct nfsmount *));
    100 void nfsargs_ntoh __P((struct nfs_args *));
    101 int nfs_fsinfo __P((struct nfsmount *, struct vnode *, struct ucred *,
    102 	struct proc *));
    103 static int nfs_mountdiskless __P((char *, char *, int, struct sockaddr_in *,
    104 	struct nfs_args *, struct proc *, struct vnode **, struct mount **));
    105 
    106 /*
    107  * nfs statfs call
    108  */
    109 int
    110 nfs_statfs(mp, sbp, p)
    111 	struct mount *mp;
    112 	register struct statfs *sbp;
    113 	struct proc *p;
    114 {
    115 	register struct vnode *vp;
    116 	register struct nfs_statfs *sfp;
    117 	register caddr_t cp;
    118 	register u_long *tl;
    119 	register long t1, t2;
    120 	caddr_t bpos, dpos, cp2;
    121 	struct nfsmount *nmp = VFSTONFS(mp);
    122 	int error = 0, v3 = (nmp->nm_flag & NFSMNT_NFSV3), retattr;
    123 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
    124 	struct ucred *cred;
    125 	struct nfsnode *np;
    126 	u_quad_t tquad;
    127 
    128 #ifndef nolint
    129 	sfp = (struct nfs_statfs *)0;
    130 #endif
    131 	error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
    132 	if (error)
    133 		return (error);
    134 	vp = NFSTOV(np);
    135 	cred = crget();
    136 	cred->cr_ngroups = 1;
    137 	if (v3 && (nmp->nm_flag & NFSMNT_GOTFSINFO) == 0)
    138 		(void)nfs_fsinfo(nmp, vp, cred, p);
    139 	nfsstats.rpccnt[NFSPROC_FSSTAT]++;
    140 	nfsm_reqhead(vp, NFSPROC_FSSTAT, NFSX_FH(v3));
    141 	nfsm_fhtom(vp, v3);
    142 	nfsm_request(vp, NFSPROC_FSSTAT, p, cred);
    143 	if (v3)
    144 		nfsm_postop_attr(vp, retattr);
    145 	if (!error)
    146 		nfsm_dissect(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
    147 	sbp->f_iosize = min(nmp->nm_rsize, nmp->nm_wsize);
    148 	if (v3) {
    149 		sbp->f_bsize = NFS_FABLKSIZE;
    150 		fxdr_hyper(&sfp->sf_tbytes, &tquad);
    151 		sbp->f_blocks = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE));
    152 		fxdr_hyper(&sfp->sf_fbytes, &tquad);
    153 		sbp->f_bfree = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE));
    154 		fxdr_hyper(&sfp->sf_abytes, &tquad);
    155 		sbp->f_bavail = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE));
    156 		sbp->f_files = (fxdr_unsigned(long, sfp->sf_tfiles.nfsuquad[1])
    157 			& 0x7fffffff);
    158 		sbp->f_ffree = (fxdr_unsigned(long, sfp->sf_ffiles.nfsuquad[1])
    159 			& 0x7fffffff);
    160 	} else {
    161 		sbp->f_bsize = fxdr_unsigned(long, sfp->sf_bsize);
    162 		sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks);
    163 		sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree);
    164 		sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail);
    165 		sbp->f_files = 0;
    166 		sbp->f_ffree = 0;
    167 	}
    168 	if (sbp != &mp->mnt_stat) {
    169 		bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
    170 		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
    171 	}
    172 	nfsm_reqdone;
    173 	vrele(vp);
    174 	crfree(cred);
    175 	return (error);
    176 }
    177 
    178 /*
    179  * nfs version 3 fsinfo rpc call
    180  */
    181 int
    182 nfs_fsinfo(nmp, vp, cred, p)
    183 	register struct nfsmount *nmp;
    184 	register struct vnode *vp;
    185 	struct ucred *cred;
    186 	struct proc *p;
    187 {
    188 	register struct nfsv3_fsinfo *fsp;
    189 	register caddr_t cp;
    190 	register long t1, t2;
    191 	register u_long *tl, pref, max;
    192 	caddr_t bpos, dpos, cp2;
    193 	int error = 0, retattr;
    194 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
    195 
    196 	nfsstats.rpccnt[NFSPROC_FSINFO]++;
    197 	nfsm_reqhead(vp, NFSPROC_FSINFO, NFSX_FH(1));
    198 	nfsm_fhtom(vp, 1);
    199 	nfsm_request(vp, NFSPROC_FSINFO, p, cred);
    200 	nfsm_postop_attr(vp, retattr);
    201 	if (!error) {
    202 		nfsm_dissect(fsp, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
    203 		pref = fxdr_unsigned(u_long, fsp->fs_wtpref);
    204 		if (pref < nmp->nm_wsize)
    205 			nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) &
    206 				~(NFS_FABLKSIZE - 1);
    207 		max = fxdr_unsigned(u_long, fsp->fs_wtmax);
    208 		if (max < nmp->nm_wsize) {
    209 			nmp->nm_wsize = max & ~(NFS_FABLKSIZE - 1);
    210 			if (nmp->nm_wsize == 0)
    211 				nmp->nm_wsize = max;
    212 		}
    213 		pref = fxdr_unsigned(u_long, fsp->fs_rtpref);
    214 		if (pref < nmp->nm_rsize)
    215 			nmp->nm_rsize = (pref + NFS_FABLKSIZE - 1) &
    216 				~(NFS_FABLKSIZE - 1);
    217 		max = fxdr_unsigned(u_long, fsp->fs_rtmax);
    218 		if (max < nmp->nm_rsize) {
    219 			nmp->nm_rsize = max & ~(NFS_FABLKSIZE - 1);
    220 			if (nmp->nm_rsize == 0)
    221 				nmp->nm_rsize = max;
    222 		}
    223 		pref = fxdr_unsigned(u_long, fsp->fs_dtpref);
    224 		if (pref < nmp->nm_readdirsize)
    225 			nmp->nm_readdirsize = (pref + NFS_DIRBLKSIZ - 1) &
    226 				~(NFS_DIRBLKSIZ - 1);
    227 		if (max < nmp->nm_readdirsize) {
    228 			nmp->nm_readdirsize = max & ~(NFS_DIRBLKSIZ - 1);
    229 			if (nmp->nm_readdirsize == 0)
    230 				nmp->nm_readdirsize = max;
    231 		}
    232 		nmp->nm_flag |= NFSMNT_GOTFSINFO;
    233 	}
    234 	nfsm_reqdone;
    235 	return (error);
    236 }
    237 
    238 /*
    239  * Mount a remote root fs via. nfs. This depends on the info in the
    240  * nfs_diskless structure that has been filled in properly by some primary
    241  * bootstrap.
    242  * It goes something like this:
    243  * - do enough of "ifconfig" by calling ifioctl() so that the system
    244  *   can talk to the server
    245  * - If nfs_diskless.mygateway is filled in, use that address as
    246  *   a default gateway.
    247  * - hand craft the swap nfs vnode hanging off a fake mount point
    248  *	if swdevt[0].sw_dev == NODEV
    249  * - build the rootfs mount point and call mountnfs() to do the rest.
    250  */
    251 int
    252 nfs_mountroot()
    253 {
    254 	struct mount *mp, *swap_mp;
    255 	struct nfs_diskless *nd = &nfs_diskless;
    256 	struct socket *so;
    257 	struct vnode *vp;
    258 	struct proc *p = curproc;		/* XXX */
    259 	int error, i;
    260 	u_long l;
    261 	char buf[128];
    262 
    263 	/*
    264 	 * XXX time must be non-zero when we init the interface or else
    265 	 * the arp code will wedge...
    266 	 */
    267 	if (time.tv_sec == 0)
    268 		time.tv_sec = 1;
    269 
    270 	/*
    271 	 * XXX splnet, so networks will receive...
    272 	 */
    273 	splnet();
    274 
    275 #ifdef notyet
    276 	/* Set up swap credentials. */
    277 	proc0.p_ucred->cr_uid = ntohl(nd->swap_ucred.cr_uid);
    278 	proc0.p_ucred->cr_gid = ntohl(nd->swap_ucred.cr_gid);
    279 	if ((proc0.p_ucred->cr_ngroups = ntohs(nd->swap_ucred.cr_ngroups)) >
    280 		NGROUPS)
    281 		proc0.p_ucred->cr_ngroups = NGROUPS;
    282 	for (i = 0; i < proc0.p_ucred->cr_ngroups; i++)
    283 	    proc0.p_ucred->cr_groups[i] = ntohl(nd->swap_ucred.cr_groups[i]);
    284 #endif
    285 
    286 	/*
    287 	 * Do enough of ifconfig(8) so that the critical net interface can
    288 	 * talk to the server.
    289 	 */
    290 	error = socreate(nd->myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0);
    291 	if (error) {
    292 		printf("nfs_mountroot: socreate(%04x): %d",
    293 			nd->myif.ifra_addr.sa_family, error);
    294 		return (error);
    295 	}
    296 
    297 	/*
    298 	 * We might not have been told the right interface, so we pass
    299 	 * over the first ten interfaces of the same kind, until we get
    300 	 * one of them configured.
    301 	 */
    302 
    303 	for (i = strlen(nd->myif.ifra_name) - 1;
    304 		nd->myif.ifra_name[i] >= '0' &&
    305 		nd->myif.ifra_name[i] <= '9';
    306 		nd->myif.ifra_name[i] ++) {
    307 		error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, p);
    308 		if(!error)
    309 			break;
    310 	}
    311 	if (error) {
    312 		printf("nfs_mountroot: SIOCAIFADDR: %d", error);
    313 		return (error);
    314 	}
    315 	soclose(so);
    316 
    317 	/*
    318 	 * If the gateway field is filled in, set it as the default route.
    319 	 */
    320 	if (nd->mygateway.sin_len != 0) {
    321 		struct sockaddr_in mask, sin;
    322 
    323 		bzero((caddr_t)&mask, sizeof(mask));
    324 		sin = mask;
    325 		sin.sin_family = AF_INET;
    326 		sin.sin_len = sizeof(sin);
    327 		error = rtrequest(RTM_ADD, (struct sockaddr *)&sin,
    328 		    (struct sockaddr *)&nd->mygateway,
    329 		    (struct sockaddr *)&mask,
    330 		    RTF_UP | RTF_GATEWAY, (struct rtentry **)0);
    331 		if (error) {
    332 			printf("nfs_mountroot: RTM_ADD: %d", error);
    333 			return (error);
    334 		}
    335 	}
    336 
    337 	swap_mp = NULL;
    338 	if (nd->swap_nblks) {
    339 		/*
    340 		 * Create a fake mount point just for the swap vnode so that the
    341 		 * swap file can be on a different server from the rootfs.
    342 		 */
    343 		nd->swap_args.fh = nd->swap_fh;
    344 		/*
    345 		 * If using nfsv3_diskless, replace NFSX_V2FH with
    346 		 * nd->swap_fhsize.
    347 		 */
    348 		nd->swap_args.fhsize = NFSX_V2FH;
    349 		l = ntohl(nd->swap_saddr.sin_addr.s_addr);
    350 		sprintf(buf,"%ld.%ld.%ld.%ld:%s",
    351 			(l >> 24) & 0xff, (l >> 16) & 0xff,
    352 			(l >>  8) & 0xff, (l >>  0) & 0xff,nd->swap_hostnam);
    353 		printf("NFS SWAP: %s\n",buf);
    354 		if (error = nfs_mountdiskless(buf, "/swap", 0,
    355 		    &nd->swap_saddr, &nd->swap_args, p, &vp, &swap_mp))
    356 			return (error);
    357 		vfs_unbusy(swap_mp, p);
    358 
    359 		for (i=0;swdevt[i].sw_dev != NODEV;i++) ;
    360 
    361 		/*
    362 		 * Since the swap file is not the root dir of a file system,
    363 		 * hack it to a regular file.
    364 		 */
    365 		vp->v_type = VREG;
    366 		vp->v_flag = 0;
    367 		swapdev_vp = vp;
    368 		VREF(vp);
    369 		swdevt[i].sw_vp = vp;
    370 		swdevt[i].sw_nblks = nd->swap_nblks*2;
    371 
    372 		if (!swdevt[i].sw_nblks) {
    373 			swdevt[i].sw_nblks = 2048;
    374 			printf("defaulting to %d kbyte.\n",
    375 				swdevt[i].sw_nblks/2);
    376 		} else
    377 			printf("using %d kbyte.\n",swdevt[i].sw_nblks/2);
    378 	}
    379 
    380 	/*
    381 	 * Create the rootfs mount point.
    382 	 */
    383 	nd->root_args.fh = nd->root_fh;
    384 	/*
    385 	 * If using nfsv3_diskless, replace NFSX_V2FH with nd->root_fhsize.
    386 	 */
    387 	nd->root_args.fhsize = NFSX_V2FH;
    388 	l = ntohl(nd->swap_saddr.sin_addr.s_addr);
    389 	sprintf(buf,"%ld.%ld.%ld.%ld:%s",
    390 		(l >> 24) & 0xff, (l >> 16) & 0xff,
    391 		(l >>  8) & 0xff, (l >>  0) & 0xff,nd->root_hostnam);
    392 	printf("NFS ROOT: %s\n",buf);
    393 	if (error = nfs_mountdiskless(buf, "/", MNT_RDONLY,
    394 	    &nd->root_saddr, &nd->root_args, p, &vp, &mp)) {
    395 		if (swap_mp) {
    396 			mp->mnt_vfc->vfc_refcount--;
    397 			free(swap_mp, M_MOUNT);
    398 		}
    399 		return (error);
    400 	}
    401 
    402 	simple_lock(&mountlist_slock);
    403 	CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
    404 	simple_unlock(&mountlist_slock);
    405 	rootvp = vp;
    406 	vfs_unbusy(mp, p);
    407 
    408 	/*
    409 	 * This is not really an nfs issue, but it is much easier to
    410 	 * set hostname here and then let the "/etc/rc.xxx" files
    411 	 * mount the right /var based upon its preset value.
    412 	 */
    413 	bcopy(nd->my_hostnam, hostname, MAXHOSTNAMELEN);
    414 	hostname[MAXHOSTNAMELEN - 1] = '\0';
    415 	for (i = 0; i < MAXHOSTNAMELEN; i++)
    416 		if (hostname[i] == '\0')
    417 			break;
    418 	hostnamelen = i;
    419 	inittodr(ntohl(nd->root_time));
    420 	return (0);
    421 }
    422 
    423 /*
    424  * Internal version of mount system call for diskless setup.
    425  */
    426 static int
    427 nfs_mountdiskless(path, which, mountflag, sin, args, p, vpp, mpp)
    428 	char *path;
    429 	char *which;
    430 	int mountflag;
    431 	struct sockaddr_in *sin;
    432 	struct nfs_args *args;
    433 	struct proc *p;
    434 	struct vnode **vpp;
    435 	struct mount **mpp;
    436 {
    437 	struct mount *mp;
    438 	struct mbuf *m;
    439 	int error;
    440 
    441 	if (error = vfs_rootmountalloc("nfs", path, &mp)) {
    442 		printf("nfs_mountroot: NFS not configured");
    443 		return (error);
    444 	}
    445 	mp->mnt_flag = mountflag;
    446 	MGET(m, MT_SONAME, M_WAITOK);
    447 	bcopy((caddr_t)sin, mtod(m, caddr_t), sin->sin_len);
    448 	m->m_len = sin->sin_len;
    449 	if (error = mountnfs(args, mp, m, which, path, vpp)) {
    450 		printf("nfs_mountroot: mount %s on %s: %d", path, which, error);
    451 		mp->mnt_vfc->vfc_refcount--;
    452 		vfs_unbusy(mp, p);
    453 		free(mp, M_MOUNT);
    454 		return (error);
    455 	}
    456 	(void) copystr(which, mp->mnt_stat.f_mntonname, MNAMELEN - 1, 0);
    457 	*mpp = mp;
    458 	return (0);
    459 }
    460 
    461 /*
    462  * VFS Operations.
    463  *
    464  * mount system call
    465  * It seems a bit dumb to copyinstr() the host and path here and then
    466  * bcopy() them in mountnfs(), but I wanted to detect errors before
    467  * doing the sockargs() call because sockargs() allocates an mbuf and
    468  * an error after that means that I have to release the mbuf.
    469  */
    470 /* ARGSUSED */
    471 int
    472 nfs_mount(mp, path, data, ndp, p)
    473 	struct mount *mp;
    474 	char *path;
    475 	caddr_t data;
    476 	struct nameidata *ndp;
    477 	struct proc *p;
    478 {
    479 	int error;
    480 	struct nfs_args args;
    481 	struct mbuf *nam;
    482 	struct vnode *vp;
    483 	char pth[MNAMELEN], hst[MNAMELEN];
    484 	u_int len;
    485 	u_char nfh[NFSX_V3FHMAX];
    486 
    487 	error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args));
    488 	if (error)
    489 		return (error);
    490 	if (args.version != NFS_ARGSVERSION)
    491 		return (EPROGMISMATCH);
    492 	error = copyin((caddr_t)args.fh, (caddr_t)nfh, args.fhsize);
    493 	if (error)
    494 		return (error);
    495 	error = copyinstr(path, pth, MNAMELEN-1, &len);
    496 	if (error)
    497 		return (error);
    498 	bzero(&pth[len], MNAMELEN - len);
    499 	error = copyinstr(args.hostname, hst, MNAMELEN-1, &len);
    500 	if (error)
    501 		return (error);
    502 	bzero(&hst[len], MNAMELEN - len);
    503 	/* sockargs() call must be after above copyin() calls */
    504 	error = sockargs(&nam, (caddr_t)args.addr, args.addrlen, MT_SONAME);
    505 	if (error)
    506 		return (error);
    507 	args.fh = nfh;
    508 	error = mountnfs(&args, mp, nam, pth, hst, &vp);
    509 	return (error);
    510 }
    511 
    512 /*
    513  * Common code for mount and mountroot
    514  */
    515 int
    516 mountnfs(argp, mp, nam, pth, hst, vpp)
    517 	register struct nfs_args *argp;
    518 	register struct mount *mp;
    519 	struct mbuf *nam;
    520 	char *pth, *hst;
    521 	struct vnode **vpp;
    522 {
    523 	register struct nfsmount *nmp;
    524 	struct nfsnode *np;
    525 	int error, maxio;
    526 
    527 	if (mp->mnt_flag & MNT_UPDATE) {
    528 		nmp = VFSTONFS(mp);
    529 		/* update paths, file handles, etc, here	XXX */
    530 		m_freem(nam);
    531 		return (0);
    532 	} else {
    533 		MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount),
    534 		    M_NFSMNT, M_WAITOK);
    535 		bzero((caddr_t)nmp, sizeof (struct nfsmount));
    536 		TAILQ_INIT(&nmp->nm_uidlruhead);
    537 		mp->mnt_data = (qaddr_t)nmp;
    538 	}
    539 	vfs_getnewfsid(mp);
    540 	nmp->nm_mountp = mp;
    541 	nmp->nm_flag = argp->flags;
    542 	if (nmp->nm_flag & NFSMNT_NQNFS)
    543 		/*
    544 		 * We have to set mnt_maxsymlink to a non-zero value so
    545 		 * that COMPAT_43 routines will know that we are setting
    546 		 * the d_type field in directories (and can zero it for
    547 		 * unsuspecting binaries).
    548 		 */
    549 		mp->mnt_maxsymlinklen = 1;
    550 	nmp->nm_timeo = NFS_TIMEO;
    551 	nmp->nm_retry = NFS_RETRANS;
    552 	nmp->nm_wsize = NFS_WSIZE;
    553 	nmp->nm_rsize = NFS_RSIZE;
    554 	nmp->nm_readdirsize = NFS_READDIRSIZE;
    555 	nmp->nm_numgrps = NFS_MAXGRPS;
    556 	nmp->nm_readahead = NFS_DEFRAHEAD;
    557 	nmp->nm_leaseterm = NQ_DEFLEASE;
    558 	nmp->nm_deadthresh = NQ_DEADTHRESH;
    559 	CIRCLEQ_INIT(&nmp->nm_timerhead);
    560 	nmp->nm_inprog = NULLVP;
    561 	nmp->nm_fhsize = argp->fhsize;
    562 	bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize);
    563 	bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
    564 	bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN);
    565 	nmp->nm_nam = nam;
    566 
    567 	if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
    568 		nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
    569 		if (nmp->nm_timeo < NFS_MINTIMEO)
    570 			nmp->nm_timeo = NFS_MINTIMEO;
    571 		else if (nmp->nm_timeo > NFS_MAXTIMEO)
    572 			nmp->nm_timeo = NFS_MAXTIMEO;
    573 	}
    574 
    575 	if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
    576 		nmp->nm_retry = argp->retrans;
    577 		if (nmp->nm_retry > NFS_MAXREXMIT)
    578 			nmp->nm_retry = NFS_MAXREXMIT;
    579 	}
    580 
    581 	if (argp->flags & NFSMNT_NFSV3) {
    582 		if (argp->sotype == SOCK_DGRAM)
    583 			maxio = NFS_MAXDGRAMDATA;
    584 		else
    585 			maxio = NFS_MAXDATA;
    586 	} else
    587 		maxio = NFS_V2MAXDATA;
    588 
    589 	if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
    590 		nmp->nm_wsize = argp->wsize;
    591 		/* Round down to multiple of blocksize */
    592 		nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1);
    593 		if (nmp->nm_wsize <= 0)
    594 			nmp->nm_wsize = NFS_FABLKSIZE;
    595 	}
    596 	if (nmp->nm_wsize > maxio)
    597 		nmp->nm_wsize = maxio;
    598 	if (nmp->nm_wsize > MAXBSIZE)
    599 		nmp->nm_wsize = MAXBSIZE;
    600 
    601 	if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
    602 		nmp->nm_rsize = argp->rsize;
    603 		/* Round down to multiple of blocksize */
    604 		nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1);
    605 		if (nmp->nm_rsize <= 0)
    606 			nmp->nm_rsize = NFS_FABLKSIZE;
    607 	}
    608 	if (nmp->nm_rsize > maxio)
    609 		nmp->nm_rsize = maxio;
    610 	if (nmp->nm_rsize > MAXBSIZE)
    611 		nmp->nm_rsize = MAXBSIZE;
    612 
    613 	if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) {
    614 		nmp->nm_readdirsize = argp->readdirsize;
    615 		/* Round down to multiple of blocksize */
    616 		nmp->nm_readdirsize &= ~(NFS_DIRBLKSIZ - 1);
    617 		if (nmp->nm_readdirsize < NFS_DIRBLKSIZ)
    618 			nmp->nm_readdirsize = NFS_DIRBLKSIZ;
    619 	}
    620 	if (nmp->nm_readdirsize > maxio)
    621 		nmp->nm_readdirsize = maxio;
    622 
    623 	if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 &&
    624 		argp->maxgrouplist <= NFS_MAXGRPS)
    625 		nmp->nm_numgrps = argp->maxgrouplist;
    626 	if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 &&
    627 		argp->readahead <= NFS_MAXRAHEAD)
    628 		nmp->nm_readahead = argp->readahead;
    629 	if ((argp->flags & NFSMNT_LEASETERM) && argp->leaseterm >= 2 &&
    630 		argp->leaseterm <= NQ_MAXLEASE)
    631 		nmp->nm_leaseterm = argp->leaseterm;
    632 	if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1 &&
    633 		argp->deadthresh <= NQ_NEVERDEAD)
    634 		nmp->nm_deadthresh = argp->deadthresh;
    635 	/* Set up the sockets and per-host congestion */
    636 	nmp->nm_sotype = argp->sotype;
    637 	nmp->nm_soproto = argp->proto;
    638 
    639 	/*
    640 	 * For Connection based sockets (TCP,...) defer the connect until
    641 	 * the first request, in case the server is not responding.
    642 	 */
    643 	if (nmp->nm_sotype == SOCK_DGRAM &&
    644 		(error = nfs_connect(nmp, (struct nfsreq *)0)))
    645 		goto bad;
    646 
    647 	/*
    648 	 * This is silly, but it has to be set so that vinifod() works.
    649 	 * We do not want to do an nfs_statfs() here since we can get
    650 	 * stuck on a dead server and we are holding a lock on the mount
    651 	 * point.
    652 	 */
    653 	mp->mnt_stat.f_iosize = NFS_MAXDGRAMDATA;
    654 	/*
    655 	 * A reference count is needed on the nfsnode representing the
    656 	 * remote root.  If this object is not persistent, then backward
    657 	 * traversals of the mount point (i.e. "..") will not work if
    658 	 * the nfsnode gets flushed out of the cache. Ufs does not have
    659 	 * this problem, because one can identify root inodes by their
    660 	 * number == ROOTINO (2).
    661 	 */
    662 	error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
    663 	if (error)
    664 		goto bad;
    665 	*vpp = NFSTOV(np);
    666 
    667 	return (0);
    668 bad:
    669 	nfs_disconnect(nmp);
    670 	free((caddr_t)nmp, M_NFSMNT);
    671 	m_freem(nam);
    672 	return (error);
    673 }
    674 
    675 /*
    676  * unmount system call
    677  */
    678 int
    679 nfs_unmount(mp, mntflags, p)
    680 	struct mount *mp;
    681 	int mntflags;
    682 	struct proc *p;
    683 {
    684 	register struct nfsmount *nmp;
    685 	struct nfsnode *np;
    686 	struct vnode *vp;
    687 	int error, flags = 0;
    688 
    689 	if (mntflags & MNT_FORCE)
    690 		flags |= FORCECLOSE;
    691 	nmp = VFSTONFS(mp);
    692 	/*
    693 	 * Goes something like this..
    694 	 * - Check for activity on the root vnode (other than ourselves).
    695 	 * - Call vflush() to clear out vnodes for this file system,
    696 	 *   except for the root vnode.
    697 	 * - Decrement reference on the vnode representing remote root.
    698 	 * - Close the socket
    699 	 * - Free up the data structures
    700 	 */
    701 	/*
    702 	 * We need to decrement the ref. count on the nfsnode representing
    703 	 * the remote root.  See comment in mountnfs().  The VFS unmount()
    704 	 * has done vput on this vnode, otherwise we would get deadlock!
    705 	 */
    706 	error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
    707 	if (error)
    708 		return(error);
    709 	vp = NFSTOV(np);
    710 	if (vp->v_usecount > 2) {
    711 		vput(vp);
    712 		return (EBUSY);
    713 	}
    714 
    715 	/*
    716 	 * Must handshake with nqnfs_clientd() if it is active.
    717 	 */
    718 	nmp->nm_flag |= NFSMNT_DISMINPROG;
    719 	while (nmp->nm_inprog != NULLVP)
    720 		(void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0);
    721 	error = vflush(mp, vp, flags);
    722 	if (error) {
    723 		vput(vp);
    724 		nmp->nm_flag &= ~NFSMNT_DISMINPROG;
    725 		return (error);
    726 	}
    727 
    728 	/*
    729 	 * We are now committed to the unmount.
    730 	 * For NQNFS, let the server daemon free the nfsmount structure.
    731 	 */
    732 	if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB))
    733 		nmp->nm_flag |= NFSMNT_DISMNT;
    734 
    735 	/*
    736 	 * There are two reference counts to get rid of here.
    737 	 */
    738 	vrele(vp);
    739 	vrele(vp);
    740 	vgone(vp);
    741 	nfs_disconnect(nmp);
    742 	m_freem(nmp->nm_nam);
    743 
    744 	if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) == 0)
    745 		free((caddr_t)nmp, M_NFSMNT);
    746 	return (0);
    747 }
    748 
    749 /*
    750  * Return root of a filesystem
    751  */
    752 int
    753 nfs_root(mp, vpp)
    754 	struct mount *mp;
    755 	struct vnode **vpp;
    756 {
    757 	register struct vnode *vp;
    758 	struct nfsmount *nmp;
    759 	struct nfsnode *np;
    760 	int error;
    761 
    762 	nmp = VFSTONFS(mp);
    763 	error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
    764 	if (error)
    765 		return (error);
    766 	vp = NFSTOV(np);
    767 	vp->v_type = VDIR;
    768 	vp->v_flag = VROOT;
    769 	*vpp = vp;
    770 	return (0);
    771 }
    772 
    773 extern int syncprt;
    774 
    775 /*
    776  * Flush out the buffer cache
    777  */
    778 /* ARGSUSED */
    779 int
    780 nfs_sync(mp, waitfor, cred, p)
    781 	struct mount *mp;
    782 	int waitfor;
    783 	struct ucred *cred;
    784 	struct proc *p;
    785 {
    786 	register struct vnode *vp;
    787 	int error, allerror = 0;
    788 
    789 	/*
    790 	 * Force stale buffer cache information to be flushed.
    791 	 */
    792 loop:
    793 	for (vp = mp->mnt_vnodelist.lh_first;
    794 	     vp != NULL;
    795 	     vp = vp->v_mntvnodes.le_next) {
    796 		/*
    797 		 * If the vnode that we are about to sync is no longer
    798 		 * associated with this mount point, start over.
    799 		 */
    800 		if (vp->v_mount != mp)
    801 			goto loop;
    802 		if (VOP_ISLOCKED(vp) || vp->v_dirtyblkhd.lh_first == NULL)
    803 			continue;
    804 		if (vget(vp, LK_EXCLUSIVE, p))
    805 			goto loop;
    806 		error = VOP_FSYNC(vp, cred, waitfor, p);
    807 		if (error)
    808 			allerror = error;
    809 		vput(vp);
    810 	}
    811 	return (allerror);
    812 }
    813 
    814 /*
    815  * NFS flat namespace lookup.
    816  * Currently unsupported.
    817  */
    818 /* ARGSUSED */
    819 int
    820 nfs_vget(mp, ino, vpp)
    821 	struct mount *mp;
    822 	ino_t ino;
    823 	struct vnode **vpp;
    824 {
    825 
    826 	return (EOPNOTSUPP);
    827 }
    828 
    829 /*
    830  * At this point, this should never happen
    831  */
    832 /* ARGSUSED */
    833 int
    834 nfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
    835 	register struct mount *mp;
    836 	struct fid *fhp;
    837 	struct mbuf *nam;
    838 	struct vnode **vpp;
    839 	int *exflagsp;
    840 	struct ucred **credanonp;
    841 {
    842 
    843 	return (EINVAL);
    844 }
    845 
    846 /*
    847  * Vnode pointer to File handle, should never happen either
    848  */
    849 /* ARGSUSED */
    850 int
    851 nfs_vptofh(vp, fhp)
    852 	struct vnode *vp;
    853 	struct fid *fhp;
    854 {
    855 
    856 	return (EINVAL);
    857 }
    858 
    859 /*
    860  * Vfs start routine, a no-op.
    861  */
    862 /* ARGSUSED */
    863 int
    864 nfs_start(mp, flags, p)
    865 	struct mount *mp;
    866 	int flags;
    867 	struct proc *p;
    868 {
    869 
    870 	return (0);
    871 }
    872 
    873 /*
    874  * Do operations associated with quotas, not supported
    875  */
    876 /* ARGSUSED */
    877 int
    878 nfs_quotactl(mp, cmd, uid, arg, p)
    879 	struct mount *mp;
    880 	int cmd;
    881 	uid_t uid;
    882 	caddr_t arg;
    883 	struct proc *p;
    884 {
    885 
    886 	return (EOPNOTSUPP);
    887 }
    888 
    889 /*
    890  * Do that sysctl thang...
    891  */
    892 static int
    893 nfs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
    894 	   size_t newlen, struct proc *p)
    895 {
    896 	int rv;
    897 
    898 	/*
    899 	 * All names at this level are terminal.
    900 	 */
    901 	if(namelen > 1)
    902 		return ENOTDIR;	/* overloaded */
    903 
    904 	switch(name[0]) {
    905 	case NFS_NFSSTATS:
    906 		if(!oldp) {
    907 			*oldlenp = sizeof nfsstats;
    908 			return 0;
    909 		}
    910 
    911 		if(*oldlenp < sizeof nfsstats) {
    912 			*oldlenp = sizeof nfsstats;
    913 			return ENOMEM;
    914 		}
    915 
    916 		rv = copyout(&nfsstats, oldp, sizeof nfsstats);
    917 		if(rv) return rv;
    918 
    919 		if(newp && newlen != sizeof nfsstats)
    920 			return EINVAL;
    921 
    922 		if(newp) {
    923 			return copyin(newp, &nfsstats, sizeof nfsstats);
    924 		}
    925 		return 0;
    926 
    927 	default:
    928 		return EOPNOTSUPP;
    929 	}
    930 }
    931 
    932