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