swdevt[0].sw_dev = NETDEV;
struct mount *nfs_mount_diskless    __P((struct nfs_dlmount *, char *, int, struct vnode **));#define TRUE	1#define	FALSE	0/* * nfs statfs call */intnfs_statfs(mp, sbp, p)	struct mount *mp;	register struct statfs *sbp;	struct proc *p;{	register struct vnode *vp;	register struct nfs_statfs *sfp = NULL;	register caddr_t cp;	register u_int32_t *tl;	register int32_t t1, t2;	caddr_t bpos, dpos, cp2;	struct nfsmount *nmp = VFSTONFS(mp);	int error = 0, v3 = (nmp->nm_flag & NFSMNT_NFSV3), retattr;	struct mbuf *mreq, *mrep = NULL, *md, *mb, *mb2;	struct ucred *cred;	struct nfsnode *np;	u_quad_t tquad;	error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);	if (error)		return (error);	vp = NFSTOV(np);	cred = crget();	cred->cr_ngroups = 0;	if (v3 && (nmp->nm_flag & NFSMNT_GOTFSINFO) == 0)		(void)nfs_fsinfo(nmp, vp, cred, p);	nfsstats.rpccnt[NFSPROC_FSSTAT]++;	nfsm_reqhead(vp, NFSPROC_FSSTAT, NFSX_FH(v3));	nfsm_fhtom(vp, v3);	nfsm_request(vp, NFSPROC_FSSTAT, p, cred);	if (v3)		nfsm_postop_attr(vp, retattr);	if (error) {		if (mrep != NULL)			m_free(mrep);		goto nfsmout;	}	nfsm_dissect(sfp, struct nfs_statfs *, NFSX_STATFS(v3));	sbp->f_flags = nmp->nm_flag;	sbp->f_iosize = min(nmp->nm_rsize, nmp->nm_wsize);	if (v3) {		sbp->f_bsize = NFS_FABLKSIZE;		tquad = fxdr_hyper(&sfp->sf_tbytes);		sbp->f_blocks = (u_int32_t)(tquad / (u_quad_t)NFS_FABLKSIZE);		tquad = fxdr_hyper(&sfp->sf_fbytes);		sbp->f_bfree = (u_int32_t)(tquad / (u_quad_t)NFS_FABLKSIZE);		tquad = fxdr_hyper(&sfp->sf_abytes);		sbp->f_bavail = (int32_t)((quad_t)tquad / (quad_t)NFS_FABLKSIZE);		sbp->f_files = (fxdr_unsigned(int32_t,		    sfp->sf_tfiles.nfsuquad[1]) & 0x7fffffff);		sbp->f_ffree = (fxdr_unsigned(int32_t,		    sfp->sf_ffiles.nfsuquad[1]) & 0x7fffffff);	} else {		sbp->f_bsize = fxdr_unsigned(int32_t, sfp->sf_bsize);		sbp->f_blocks = fxdr_unsigned(int32_t, sfp->sf_blocks);		sbp->f_bfree = fxdr_unsigned(int32_t, sfp->sf_bfree);		sbp->f_bavail = fxdr_unsigned(int32_t, sfp->sf_bavail);		sbp->f_files = 0;		sbp->f_ffree = 0;	}	if (sbp != &mp->mnt_stat) {		bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);		bcopy(&mp->mnt_stat.mount_info.nfs_args,		    &sbp->mount_info.nfs_args, sizeof(struct nfs_args));	}	strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name, MFSNAMELEN);	nfsm_reqdone;	vrele(vp);	crfree(cred);	return (error);}/* * nfs version 3 fsinfo rpc call */intnfs_fsinfo(nmp, vp, cred, p)	register struct nfsmount *nmp;	register struct vnode *vp;	struct ucred *cred;	struct proc *p;{	register struct nfsv3_fsinfo *fsp;	register caddr_t cp;	register int32_t t1, t2;	register u_int32_t *tl, pref, max;	caddr_t bpos, dpos, cp2;	int error = 0, retattr;	struct mbuf *mreq, *mrep, *md, *mb, *mb2;	nfsstats.rpccnt[NFSPROC_FSINFO]++;	nfsm_reqhead(vp, NFSPROC_FSINFO, NFSX_FH(1));	nfsm_fhtom(vp, 1);	nfsm_request(vp, NFSPROC_FSINFO, p, cred);	nfsm_postop_attr(vp, retattr);	if (!error) {		nfsm_dissect(fsp, struct nfsv3_fsinfo *, NFSX_V3FSINFO);		pref = fxdr_unsigned(u_int32_t, fsp->fs_wtpref);		if (pref < nmp->nm_wsize)			nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) &				~(NFS_FABLKSIZE - 1);		max = fxdr_unsigned(u_int32_t, fsp->fs_wtmax);		if (max < nmp->nm_wsize) {			nmp->nm_wsize = max & ~(NFS_FABLKSIZE - 1);			if (nmp->nm_wsize == 0)				nmp->nm_wsize = max;		}		pref = fxdr_unsigned(u_int32_t, fsp->fs_rtpref);		if (pref < nmp->nm_rsize)			nmp->nm_rsize = (pref + NFS_FABLKSIZE - 1) &				~(NFS_FABLKSIZE - 1);		max = fxdr_unsigned(u_int32_t, fsp->fs_rtmax);		if (max < nmp->nm_rsize) {			nmp->nm_rsize = max & ~(NFS_FABLKSIZE - 1);			if (nmp->nm_rsize == 0)				nmp->nm_rsize = max;		}		pref = fxdr_unsigned(u_int32_t, fsp->fs_dtpref);		if (pref < nmp->nm_readdirsize)			nmp->nm_readdirsize = (pref + NFS_DIRBLKSIZ - 1) &				~(NFS_DIRBLKSIZ - 1);		if (max < nmp->nm_readdirsize) {			nmp->nm_readdirsize = max & ~(NFS_DIRBLKSIZ - 1);			if (nmp->nm_readdirsize == 0)				nmp->nm_readdirsize = max;		}		nmp->nm_flag |= NFSMNT_GOTFSINFO;	}	nfsm_reqdone;	return (error);}/* * Mount a remote root fs via. NFS.  It goes like this: * - Call nfs_boot_init() to fill in the nfs_diskless struct *   (using RARP, bootparam RPC, mountd RPC) * - hand craft the swap nfs vnode hanging off a fake mount point *	if swdevt[0].sw_dev == NODEV * - build the rootfs mount point and call mountnfs() to do the rest. */intnfs_mountroot(){	struct nfs_diskless nd;	struct vattr attr;	struct mount *mp;	struct vnode *vp;	struct proc *procp;	long n;	int error;	procp = curproc; /* XXX */	/*	 * XXX time must be non-zero when we init the interface or else	 * the arp code will wedge.  [Fixed now in if_ether.c]	 * However, the NFS attribute cache gives false "hits" when	 * time.tv_sec < NFS_ATTRTIMEO(np) so keep this in for now.	 */	if (time.tv_sec < NFS_MAXATTRTIMO)		time.tv_sec = NFS_MAXATTRTIMO;	/*	 * Call nfs_boot_init() to fill in the nfs_diskless struct.	 * Side effect:  Finds and configures a network interface.	 */	bzero((caddr_t) &nd, sizeof(nd));	nfs_boot_init(&nd, procp);	/*	 * Create the root mount point.	 */	nfs_boot_getfh(&nd.nd_boot, "root", &nd.nd_root);	mp = nfs_mount_diskless(&nd.nd_root, "/", 0, &vp);	printf("root on %s\n", nd.nd_root.ndm_host);	/*	 * Link it into the mount list.	 */	simple_lock(&mountlist_slock);	CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);	simple_unlock(&mountlist_slock);	rootvp = vp;	vfs_unbusy(mp, procp);	/* Get root attributes (for the time). */	error = VOP_GETATTR(vp, &attr, procp->p_ucred, procp);	if (error) panic("nfs_mountroot: getattr for root");	n = attr.va_mtime.tv_sec;#ifdef	DEBUG	printf("root time: 0x%lx\n", n);#endif	inittodr(n);	/* 	 * XXX splnet, so networks will receive...	 */	splnet();#ifdef notyet	/* Set up swap credentials. */	proc0.p_ucred->cr_uid = ntohl(nd.swap_ucred.cr_uid);	proc0.p_ucred->cr_gid = ntohl(nd.swap_ucred.cr_gid);	if ((proc0.p_ucred->cr_ngroups = ntohs(nd.swap_ucred.cr_ngroups)) >		NGROUPS)		proc0.p_ucred->cr_ngroups = NGROUPS;	for (i = 0; i < proc0.p_ucred->cr_ngroups; i++)	    proc0.p_ucred->cr_groups[i] = ntohl(nd.swap_ucred.cr_groups[i]);#endif	/*	 * "Mount" the swap device.	 *	 * On a "dataless" configuration (swap on disk) we will have:	 *	(swdevt[0].sw_dev != NODEV) identifying the swap device.	 */	if (bdevvp(swapdev, &swapdev_vp))		panic("nfs_mountroot: can't setup swap vp");	if (swdevt[0].sw_dev != NODEV) {		printf("swap on device 0x%x\n", swdevt[0].sw_dev);		return (0);	}	/*	 * If swapping to an nfs node:  (swdevt[0].sw_dev == NODEV)	 * Create a fake mount point just for the swap vnode so that the	 * swap file can be on a different server from the rootfs.	 */	nfs_boot_getfh(&nd.nd_boot, "swap", &nd.nd_swap);	mp = nfs_mount_diskless(&nd.nd_swap, "/swap", 0, &vp);	vfs_unbusy(mp, procp);	printf("swap on %s\n", nd.nd_swap.ndm_host);	/*	 * Since the swap file is not the root dir of a file system,	 * hack it to a regular file.	 */	vp->v_type = VREG;	vp->v_flag = 0;	swdevt[0].sw_vp = vp;	/*	 * Find out how large the swap file is.	 */	error = VOP_GETATTR(vp, &attr, procp->p_ucred, procp);	if (error)		panic("nfs_mountroot: getattr for swap");	n = (long) (attr.va_size >> DEV_BSHIFT);#ifdef	DEBUG	printf("swap size: 0x%lx (blocks)\n", n);#endif	swdevt[0].sw_nblks = n;	return (0);}/* * Internal version of mount system call for diskless setup. */struct mount *nfs_mount_diskless(ndmntp, mntname, mntflag, vpp)	struct nfs_dlmount *ndmntp;	char *mntname;	int mntflag;	struct vnode **vpp;{	struct nfs_args args;	struct mount *mp;	struct mbuf *m;	int error;	if (vfs_rootmountalloc("nfs", mntname, &mp))		panic("nfs_mount_diskless: vfs_rootmountalloc failed");	mp->mnt_flag |= mntflag;	/* Initialize mount args. */	bzero((caddr_t) &args, sizeof(args));	args.addr     = (struct sockaddr *)&ndmntp->ndm_saddr;	args.addrlen  = args.addr->sa_len;	args.sotype   = SOCK_DGRAM;	args.fh       = ndmntp->ndm_fh;	args.fhsize   = NFSX_V2FH;	args.hostname = ndmntp->ndm_host;#ifdef	NFS_BOOT_OPTIONS	args.flags    |= NFS_BOOT_OPTIONS;#endif#ifdef	NFS_BOOT_RWSIZE	/*	 * Reduce rsize,wsize for interfaces that consistently	 * drop fragments of long UDP messages.  (i.e. wd8003).	 * You can always change these later via remount.	 */	args.flags   |= NFSMNT_WSIZE | NFSMNT_RSIZE;	args.wsize    = NFS_BOOT_RWSIZE;	args.rsize    = NFS_BOOT_RWSIZE;#endif	/* Get mbuf for server sockaddr. */	m = m_get(M_WAIT, MT_SONAME);	if (m == NULL)		panic("nfs_mountroot: mget soname for %s", mntname);	bcopy((caddr_t)args.addr, mtod(m, caddr_t),	    (m->m_len = args.addr->sa_len));	error = mountnfs(&args, mp, m, mntname, args.hostname, vpp);	if (error)		panic("nfs_mountroot: mount %s failed: %d", mntname, error);	return (mp);}