138414Smckusick /* 238414Smckusick * Copyright (c) 1989 The Regents of the University of California. 338414Smckusick * All rights reserved. 438414Smckusick * 538414Smckusick * This code is derived from software contributed to Berkeley by 638414Smckusick * Rick Macklem at The University of Guelph. 738414Smckusick * 844513Sbostic * %sccs.include.redist.c% 938414Smckusick * 10*47573Skarels * @(#)nfs_vfsops.c 7.26 (Berkeley) 03/19/91 1138414Smckusick */ 1238414Smckusick 1338414Smckusick #include "param.h" 1446988Smckusick #include "conf.h" 1546988Smckusick #include "ioctl.h" 1638414Smckusick #include "signal.h" 1738414Smckusick #include "proc.h" 1838414Smckusick #include "vnode.h" 1938414Smckusick #include "mount.h" 2040120Smckusick #include "buf.h" 2138414Smckusick #include "mbuf.h" 2238414Smckusick #include "socket.h" 2340120Smckusick #include "systm.h" 24*47573Skarels 2546988Smckusick #include "../net/if.h" 2646988Smckusick #include "../net/route.h" 2746988Smckusick #include "../netinet/in.h" 28*47573Skarels 2938414Smckusick #include "nfsv2.h" 3038414Smckusick #include "nfsnode.h" 3138414Smckusick #include "nfsmount.h" 3238414Smckusick #include "nfs.h" 3341904Smckusick #include "xdr_subs.h" 3441904Smckusick #include "nfsm_subs.h" 3546988Smckusick #include "nfsdiskless.h" 3638414Smckusick 3738414Smckusick /* 3838414Smckusick * nfs vfs operations. 3938414Smckusick */ 4038414Smckusick int nfs_mount(); 4138874Smckusick int nfs_start(); 4238414Smckusick int nfs_unmount(); 4338414Smckusick int nfs_root(); 4441294Smckusick int nfs_quotactl(); 4539443Smckusick int nfs_statfs(); 4638414Smckusick int nfs_sync(); 4738414Smckusick int nfs_fhtovp(); 4838414Smckusick int nfs_vptofh(); 4939443Smckusick int nfs_init(); 5038414Smckusick 5138414Smckusick struct vfsops nfs_vfsops = { 5238414Smckusick nfs_mount, 5338874Smckusick nfs_start, 5438414Smckusick nfs_unmount, 5538414Smckusick nfs_root, 5641294Smckusick nfs_quotactl, 5738414Smckusick nfs_statfs, 5838414Smckusick nfs_sync, 5938414Smckusick nfs_fhtovp, 6038414Smckusick nfs_vptofh, 6139443Smckusick nfs_init, 6238414Smckusick }; 6338414Smckusick 6439757Smckusick static u_char nfs_mntid; 6541904Smckusick extern u_long nfs_procids[NFS_NPROCS]; 6641904Smckusick extern u_long nfs_prog, nfs_vers; 6746988Smckusick struct nfs_diskless nfs_diskless; 6841904Smckusick void nfs_disconnect(); 6938414Smckusick 7041904Smckusick #define TRUE 1 7141904Smckusick #define FALSE 0 7241904Smckusick 7338414Smckusick /* 7441904Smckusick * nfs statfs call 7541904Smckusick */ 7641904Smckusick nfs_statfs(mp, sbp) 7741904Smckusick struct mount *mp; 7841904Smckusick register struct statfs *sbp; 7941904Smckusick { 8041904Smckusick register struct vnode *vp; 8141904Smckusick register struct nfsv2_statfs *sfp; 8241904Smckusick register caddr_t cp; 8341904Smckusick register long t1; 8441904Smckusick caddr_t bpos, dpos, cp2; 8541904Smckusick u_long xid; 8641904Smckusick int error = 0; 8741904Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 8841904Smckusick struct nfsmount *nmp; 8941904Smckusick struct ucred *cred; 9041904Smckusick struct nfsnode *np; 9141904Smckusick 9241904Smckusick nmp = VFSTONFS(mp); 9341904Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 9441904Smckusick return (error); 9541904Smckusick vp = NFSTOV(np); 9641904Smckusick nfsstats.rpccnt[NFSPROC_STATFS]++; 9741904Smckusick cred = crget(); 9841904Smckusick cred->cr_ngroups = 1; 9941904Smckusick nfsm_reqhead(nfs_procids[NFSPROC_STATFS], cred, NFSX_FH); 10041904Smckusick nfsm_fhtom(vp); 101*47573Skarels nfsm_request(vp, NFSPROC_STATFS, curproc, 0); 10241904Smckusick nfsm_disect(sfp, struct nfsv2_statfs *, NFSX_STATFS); 10341904Smckusick sbp->f_type = MOUNT_NFS; 10441904Smckusick sbp->f_flags = nmp->nm_flag; 10541904Smckusick sbp->f_bsize = fxdr_unsigned(long, sfp->sf_tsize); 10641904Smckusick sbp->f_fsize = fxdr_unsigned(long, sfp->sf_bsize); 10741904Smckusick sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks); 10841904Smckusick sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree); 10941904Smckusick sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail); 11041904Smckusick sbp->f_files = 0; 11141904Smckusick sbp->f_ffree = 0; 11241904Smckusick if (sbp != &mp->mnt_stat) { 11341904Smckusick bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 11441904Smckusick bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 11541904Smckusick } 11641904Smckusick nfsm_reqdone; 11741904Smckusick nfs_nput(vp); 11841904Smckusick crfree(cred); 11941904Smckusick return (error); 12041904Smckusick } 12141904Smckusick 12241904Smckusick /* 12346988Smckusick * Mount a remote root fs via. nfs. This depends on the info in the 12446988Smckusick * nfs_diskless structure that has been filled in properly by some primary 12546988Smckusick * bootstrap. 12646988Smckusick * It goes something like this: 12746988Smckusick * - do enough of "ifconfig" by calling ifioctl() so that the system 12846988Smckusick * can talk to the server 12946988Smckusick * - If nfs_diskless.mygateway is filled in, use that address as 13046988Smckusick * a default gateway. 13146988Smckusick * (This is done the 4.3 way with rtioctl() and should be changed) 13246988Smckusick * - hand craft the swap nfs vnode hanging off a fake mount point 13346988Smckusick * - build the rootfs mount point and call mountnfs() to do the rest. 13438414Smckusick */ 13538414Smckusick nfs_mountroot() 13638414Smckusick { 13746988Smckusick register struct mount *mp; 13846988Smckusick register struct mbuf *m; 13946988Smckusick struct socket *so; 14046988Smckusick struct vnode *vp; 14146988Smckusick int error; 14246988Smckusick 14346988Smckusick /* 14446988Smckusick * Do enough of ifconfig(8) so that critical net interface can 14546988Smckusick * talk to the server. 14646988Smckusick */ 14746988Smckusick if (socreate(nfs_diskless.myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0)) 14846988Smckusick panic("nfs ifconf"); 14946988Smckusick if (ifioctl(so, SIOCAIFADDR, &nfs_diskless.myif)) 15046988Smckusick panic("nfs ifconf2"); 15146988Smckusick soclose(so); 15246988Smckusick 15346988Smckusick /* 15446988Smckusick * If the gateway field is filled in, set it as the default route. 15546988Smckusick */ 15646988Smckusick #ifdef COMPAT_43 15746988Smckusick if (nfs_diskless.mygateway.sa_family == AF_INET) { 15846988Smckusick struct ortentry rt; 15946988Smckusick struct sockaddr_in *sin; 16046988Smckusick 16146988Smckusick sin = (struct sockaddr_in *) &rt.rt_dst; 16246988Smckusick sin->sin_len = sizeof (struct sockaddr_in); 16346988Smckusick sin->sin_family = AF_INET; 16446988Smckusick sin->sin_addr.s_addr = 0; /* default */ 16546988Smckusick bcopy((caddr_t)&nfs_diskless.mygateway, (caddr_t)&rt.rt_gateway, 16646988Smckusick sizeof (struct sockaddr_in)); 16746988Smckusick rt.rt_flags = (RTF_UP | RTF_GATEWAY); 16846988Smckusick if (rtioctl(SIOCADDRT, (caddr_t)&rt)) 16946988Smckusick panic("nfs root route"); 17046988Smckusick } 17146988Smckusick #endif /* COMPAT_43 */ 17246988Smckusick 17346988Smckusick /* 17446988Smckusick * If swapping to an nfs node (indicated by swdevt[0].sw_dev == NODEV): 17546988Smckusick * Create a fake mount point just for the swap vnode so that the 17646988Smckusick * swap file can be on a different server from the rootfs. 17746988Smckusick */ 17846988Smckusick if (swdevt[0].sw_dev == NODEV) { 17946988Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 18046988Smckusick M_MOUNT, M_NOWAIT); 18146988Smckusick if (mp == NULL) 18246988Smckusick panic("nfs root mount"); 18346988Smckusick mp->mnt_op = &nfs_vfsops; 18446988Smckusick mp->mnt_flag = 0; 18546988Smckusick mp->mnt_exroot = 0; 18646988Smckusick mp->mnt_mounth = NULLVP; 18746988Smckusick 18846988Smckusick /* 18946988Smckusick * Set up the diskless nfs_args for the swap mount point 19046988Smckusick * and then call mountnfs() to mount it. 19146988Smckusick * Since the swap file is not the root dir of a file system, 19246988Smckusick * hack it to a regular file. 19346988Smckusick */ 19446988Smckusick nfs_diskless.swap_args.fh = (nfsv2fh_t *)nfs_diskless.swap_fh; 19546988Smckusick MGET(m, MT_SONAME, M_DONTWAIT); 19646988Smckusick if (m == NULL) 19746988Smckusick panic("nfs root mbuf"); 19846988Smckusick bcopy((caddr_t)&nfs_diskless.swap_saddr, mtod(m, caddr_t), 19946988Smckusick nfs_diskless.swap_saddr.sa_len); 20046988Smckusick m->m_len = nfs_diskless.swap_saddr.sa_len; 20146988Smckusick if (mountnfs(&nfs_diskless.swap_args, mp, m, "/swap", 20246988Smckusick nfs_diskless.swap_hostnam, &vp)) 20346988Smckusick panic("nfs swap"); 20446988Smckusick vp->v_type = VREG; 20546988Smckusick vp->v_flag = 0; 20646988Smckusick swapdev_vp = vp; 20746988Smckusick VREF(vp); 20846988Smckusick swdevt[0].sw_vp = vp; 20946988Smckusick VREF(vp); 21046988Smckusick argdev_vp = vp; 21146988Smckusick } 21246988Smckusick 21346988Smckusick /* 21446988Smckusick * Create the rootfs mount point. 21546988Smckusick */ 21646988Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 21746988Smckusick M_MOUNT, M_NOWAIT); 21846988Smckusick if (mp == NULL) 21946988Smckusick panic("nfs root mount2"); 22046988Smckusick mp->mnt_op = &nfs_vfsops; 22146988Smckusick mp->mnt_flag = MNT_RDONLY; 22246988Smckusick mp->mnt_exroot = 0; 22346988Smckusick mp->mnt_mounth = NULLVP; 22446988Smckusick 22546988Smckusick /* 22646988Smckusick * Set up the root fs args and call mountnfs() to do the rest. 22746988Smckusick */ 22846988Smckusick nfs_diskless.root_args.fh = (nfsv2fh_t *)nfs_diskless.root_fh; 22946988Smckusick MGET(m, MT_SONAME, M_DONTWAIT); 23046988Smckusick if (m == NULL) 23146988Smckusick panic("nfs root mbuf2"); 23246988Smckusick bcopy((caddr_t)&nfs_diskless.root_saddr, mtod(m, caddr_t), 23346988Smckusick nfs_diskless.root_saddr.sa_len); 23446988Smckusick m->m_len = nfs_diskless.root_saddr.sa_len; 23546988Smckusick if (mountnfs(&nfs_diskless.root_args, mp, m, "/", 23646988Smckusick nfs_diskless.root_hostnam, &vp)) 23746988Smckusick panic("nfs root"); 23846988Smckusick if (vfs_lock(mp)) 23946988Smckusick panic("nfs root2"); 24046988Smckusick rootfs = mp; 24146988Smckusick mp->mnt_next = mp; 24246988Smckusick mp->mnt_prev = mp; 24346988Smckusick mp->mnt_vnodecovered = NULLVP; 24446988Smckusick vfs_unlock(mp); 24546988Smckusick rootvp = vp; 24646988Smckusick inittodr((time_t)0); /* There is no time in the nfs fsstat so ?? */ 24746988Smckusick return (0); 24838414Smckusick } 24938414Smckusick 25038414Smckusick /* 25138414Smckusick * VFS Operations. 25238414Smckusick * 25338414Smckusick * mount system call 25438414Smckusick * It seems a bit dumb to copyinstr() the host and path here and then 25538414Smckusick * bcopy() them in mountnfs(), but I wanted to detect errors before 25638414Smckusick * doing the sockargs() call because sockargs() allocates an mbuf and 25738414Smckusick * an error after that means that I have to release the mbuf. 25838414Smckusick */ 25939494Smckusick /* ARGSUSED */ 26038414Smckusick nfs_mount(mp, path, data, ndp) 26138414Smckusick struct mount *mp; 26238414Smckusick char *path; 26338414Smckusick caddr_t data; 26438414Smckusick struct nameidata *ndp; 26538414Smckusick { 26638414Smckusick int error; 26738414Smckusick struct nfs_args args; 26841904Smckusick struct mbuf *nam; 26946988Smckusick struct vnode *vp; 27038414Smckusick char pth[MNAMELEN], hst[MNAMELEN]; 27138414Smckusick int len; 27238414Smckusick nfsv2fh_t nfh; 27338414Smckusick 27441398Smckusick if (mp->mnt_flag & MNT_UPDATE) 27539460Smckusick return (0); 27638414Smckusick if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args))) 27738414Smckusick return (error); 27838414Smckusick if (error=copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t))) 27938414Smckusick return (error); 28038414Smckusick if (error = copyinstr(path, pth, MNAMELEN-1, &len)) 28138414Smckusick return (error); 28238414Smckusick bzero(&pth[len], MNAMELEN-len); 28338414Smckusick if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len)) 28438414Smckusick return (error); 28538414Smckusick bzero(&hst[len], MNAMELEN-len); 28638414Smckusick /* sockargs() call must be after above copyin() calls */ 28741904Smckusick if (error = sockargs(&nam, (caddr_t)args.addr, 28840120Smckusick sizeof (struct sockaddr), MT_SONAME)) 28938414Smckusick return (error); 29038414Smckusick args.fh = &nfh; 29146988Smckusick error = mountnfs(&args, mp, nam, pth, hst, &vp); 29238414Smckusick return (error); 29338414Smckusick } 29438414Smckusick 29538414Smckusick /* 29638414Smckusick * Common code for mount and mountroot 29738414Smckusick */ 29846988Smckusick mountnfs(argp, mp, nam, pth, hst, vpp) 29938414Smckusick register struct nfs_args *argp; 30038414Smckusick register struct mount *mp; 30141904Smckusick struct mbuf *nam; 30238414Smckusick char *pth, *hst; 30346988Smckusick struct vnode **vpp; 30438414Smckusick { 30538414Smckusick register struct nfsmount *nmp; 30640010Smckusick struct nfsnode *np; 30740120Smckusick int error; 30839757Smckusick fsid_t tfsid; 30938414Smckusick 31040120Smckusick MALLOC(nmp, struct nfsmount *, sizeof *nmp, M_NFSMNT, M_WAITOK); 31140120Smckusick bzero((caddr_t)nmp, sizeof *nmp); 31241398Smckusick mp->mnt_data = (qaddr_t)nmp; 31339757Smckusick /* 31439757Smckusick * Generate a unique nfs mount id. The problem is that a dev number 31539757Smckusick * is not unique across multiple systems. The techique is as follows: 31639757Smckusick * 1) Set to nblkdev,0 which will never be used otherwise 31739757Smckusick * 2) Generate a first guess as nblkdev,nfs_mntid where nfs_mntid is 31839757Smckusick * NOT 0 31939757Smckusick * 3) Loop searching the mount list for another one with same id 32039757Smckusick * If a match, increment val[0] and try again 32139757Smckusick * NB: I increment val[0] { a long } instead of nfs_mntid { a u_char } 32239757Smckusick * so that nfs is not limited to 255 mount points 32339757Smckusick * Incrementing the high order bits does no real harm, since it 32439757Smckusick * simply makes the major dev number tick up. The upper bound is 32539757Smckusick * set to major dev 127 to avoid any sign extention problems 32639757Smckusick */ 32741398Smckusick mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev, 0); 32841398Smckusick mp->mnt_stat.f_fsid.val[1] = MOUNT_NFS; 32939757Smckusick if (++nfs_mntid == 0) 33039757Smckusick ++nfs_mntid; 33139757Smckusick tfsid.val[0] = makedev(nblkdev, nfs_mntid); 33239757Smckusick tfsid.val[1] = MOUNT_NFS; 33346988Smckusick while (rootfs && getvfs(&tfsid)) { 33439757Smckusick tfsid.val[0]++; 33539757Smckusick nfs_mntid++; 33639757Smckusick } 33739757Smckusick if (major(tfsid.val[0]) > 127) { 33839757Smckusick error = ENOENT; 33939757Smckusick goto bad; 34039757Smckusick } 34141398Smckusick mp->mnt_stat.f_fsid.val[0] = tfsid.val[0]; 34238414Smckusick nmp->nm_mountp = mp; 34338414Smckusick nmp->nm_flag = argp->flags; 34440120Smckusick nmp->nm_rto = NFS_TIMEO; 34540120Smckusick nmp->nm_rtt = -1; 34640120Smckusick nmp->nm_rttvar = nmp->nm_rto << 1; 34740120Smckusick nmp->nm_retry = NFS_RETRANS; 34840120Smckusick nmp->nm_wsize = NFS_WSIZE; 34940120Smckusick nmp->nm_rsize = NFS_RSIZE; 35040120Smckusick bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t)); 35141398Smckusick mp->mnt_stat.f_type = MOUNT_NFS; 35241398Smckusick bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); 35341398Smckusick bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN); 35441904Smckusick nmp->nm_nam = nam; 35540120Smckusick 35640120Smckusick if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { 35740120Smckusick nmp->nm_rto = argp->timeo; 35840120Smckusick /* NFS timeouts are specified in 1/10 sec. */ 35940120Smckusick nmp->nm_rto = (nmp->nm_rto * 10) / NFS_HZ; 36040120Smckusick if (nmp->nm_rto < NFS_MINTIMEO) 36140120Smckusick nmp->nm_rto = NFS_MINTIMEO; 36240120Smckusick else if (nmp->nm_rto > NFS_MAXTIMEO) 36340120Smckusick nmp->nm_rto = NFS_MAXTIMEO; 36440120Smckusick nmp->nm_rttvar = nmp->nm_rto << 1; 36540120Smckusick } 36640120Smckusick 36743355Smckusick if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) { 36840120Smckusick nmp->nm_retry = argp->retrans; 36940120Smckusick if (nmp->nm_retry > NFS_MAXREXMIT) 37040120Smckusick nmp->nm_retry = NFS_MAXREXMIT; 37140120Smckusick } 37240120Smckusick 37340120Smckusick if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { 37438414Smckusick nmp->nm_wsize = argp->wsize; 37540120Smckusick /* Round down to multiple of blocksize */ 37640120Smckusick nmp->nm_wsize &= ~0x1ff; 37740120Smckusick if (nmp->nm_wsize <= 0) 37840120Smckusick nmp->nm_wsize = 512; 37940120Smckusick else if (nmp->nm_wsize > NFS_MAXDATA) 38040120Smckusick nmp->nm_wsize = NFS_MAXDATA; 38140120Smckusick } 38243355Smckusick if (nmp->nm_wsize > MAXBSIZE) 38343355Smckusick nmp->nm_wsize = MAXBSIZE; 38440120Smckusick 38540120Smckusick if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { 38638414Smckusick nmp->nm_rsize = argp->rsize; 38740120Smckusick /* Round down to multiple of blocksize */ 38840120Smckusick nmp->nm_rsize &= ~0x1ff; 38940120Smckusick if (nmp->nm_rsize <= 0) 39040120Smckusick nmp->nm_rsize = 512; 39140120Smckusick else if (nmp->nm_rsize > NFS_MAXDATA) 39240120Smckusick nmp->nm_rsize = NFS_MAXDATA; 39340120Smckusick } 39443355Smckusick if (nmp->nm_rsize > MAXBSIZE) 39543355Smckusick nmp->nm_rsize = MAXBSIZE; 39640120Smckusick /* Set up the sockets and per-host congestion */ 39741904Smckusick nmp->nm_sotype = argp->sotype; 39841904Smckusick nmp->nm_soproto = argp->proto; 39941904Smckusick if (error = nfs_connect(nmp)) 40040120Smckusick goto bad; 40140120Smckusick 40241398Smckusick if (error = nfs_statfs(mp, &mp->mnt_stat)) 40340353Smckusick goto bad; 40438414Smckusick /* 40540010Smckusick * A reference count is needed on the nfsnode representing the 40640010Smckusick * remote root. If this object is not persistent, then backward 40740010Smckusick * traversals of the mount point (i.e. "..") will not work if 40840010Smckusick * the nfsnode gets flushed out of the cache. Ufs does not have 40940010Smckusick * this problem, because one can identify root inodes by their 41040010Smckusick * number == ROOTINO (2). 41140010Smckusick */ 41240010Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 41340010Smckusick goto bad; 41440010Smckusick /* 41540010Smckusick * Unlock it, but keep the reference count. 41640010Smckusick */ 41740010Smckusick nfs_unlock(NFSTOV(np)); 41846988Smckusick *vpp = NFSTOV(np); 41941904Smckusick 42040353Smckusick return (0); 42138414Smckusick bad: 42240120Smckusick nfs_disconnect(nmp); 42340120Smckusick FREE(nmp, M_NFSMNT); 42441904Smckusick m_freem(nam); 42538414Smckusick return (error); 42638414Smckusick } 42738414Smckusick 42838414Smckusick /* 42938414Smckusick * unmount system call 43038414Smckusick */ 43141294Smckusick nfs_unmount(mp, mntflags) 43238414Smckusick struct mount *mp; 43341294Smckusick int mntflags; 43438414Smckusick { 43538414Smckusick register struct nfsmount *nmp; 43640010Smckusick struct nfsnode *np; 43740120Smckusick struct vnode *vp; 43841294Smckusick int flags = 0; 43938414Smckusick int error; 44038414Smckusick 44141294Smckusick if (mntflags & MNT_FORCE) 44238414Smckusick return (EINVAL); 44341294Smckusick if (mntflags & MNT_FORCE) 44441294Smckusick flags |= FORCECLOSE; 44541398Smckusick nmp = VFSTONFS(mp); 44638414Smckusick /* 44738884Smacklem * Clear out the buffer cache 44838884Smacklem */ 44939669Smckusick mntflushbuf(mp, 0); 45039669Smckusick if (mntinvalbuf(mp)) 45138884Smacklem return (EBUSY); 45238884Smacklem /* 45338414Smckusick * Goes something like this.. 45440120Smckusick * - Check for activity on the root vnode (other than ourselves). 45540120Smckusick * - Call vflush() to clear out vnodes for this file system, 45640120Smckusick * except for the root vnode. 45740120Smckusick * - Decrement reference on the vnode representing remote root. 45838414Smckusick * - Close the socket 45938414Smckusick * - Free up the data structures 46038414Smckusick */ 46140010Smckusick /* 46240010Smckusick * We need to decrement the ref. count on the nfsnode representing 46340010Smckusick * the remote root. See comment in mountnfs(). The VFS unmount() 46440010Smckusick * has done vput on this vnode, otherwise we would get deadlock! 46540010Smckusick */ 46640010Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 46740010Smckusick return(error); 46840120Smckusick vp = NFSTOV(np); 46940120Smckusick if (vp->v_usecount > 2) { 47040120Smckusick vput(vp); 47140120Smckusick return (EBUSY); 47240120Smckusick } 47340120Smckusick if (error = vflush(mp, vp, flags)) { 47440120Smckusick vput(vp); 47540120Smckusick return (error); 47640120Smckusick } 47740010Smckusick /* 47840010Smckusick * Get rid of two reference counts, and unlock it on the second. 47940010Smckusick */ 48040120Smckusick vrele(vp); 48140120Smckusick vput(vp); 48240120Smckusick nfs_disconnect(nmp); 48341904Smckusick m_freem(nmp->nm_nam); 48438414Smckusick free((caddr_t)nmp, M_NFSMNT); 48538414Smckusick return (0); 48638414Smckusick } 48738414Smckusick 48838414Smckusick /* 48938414Smckusick * Return root of a filesystem 49038414Smckusick */ 49138414Smckusick nfs_root(mp, vpp) 49238414Smckusick struct mount *mp; 49338414Smckusick struct vnode **vpp; 49438414Smckusick { 49538414Smckusick register struct vnode *vp; 49638414Smckusick struct nfsmount *nmp; 49738414Smckusick struct nfsnode *np; 49838414Smckusick int error; 49938414Smckusick 50041398Smckusick nmp = VFSTONFS(mp); 50138414Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 50238414Smckusick return (error); 50338414Smckusick vp = NFSTOV(np); 50438414Smckusick vp->v_type = VDIR; 50538414Smckusick vp->v_flag = VROOT; 50638414Smckusick *vpp = vp; 50738414Smckusick return (0); 50838414Smckusick } 50938414Smckusick 51038884Smacklem extern int syncprt; 51138884Smacklem 51238414Smckusick /* 51338884Smacklem * Flush out the buffer cache 51438414Smckusick */ 51539494Smckusick /* ARGSUSED */ 51638414Smckusick nfs_sync(mp, waitfor) 51738414Smckusick struct mount *mp; 51838414Smckusick int waitfor; 51938414Smckusick { 52038884Smacklem if (syncprt) 52138884Smacklem bufstats(); 52238884Smacklem /* 52338884Smacklem * Force stale buffer cache information to be flushed. 52438884Smacklem */ 52540035Smckusick mntflushbuf(mp, waitfor == MNT_WAIT ? B_SYNC : 0); 52638414Smckusick return (0); 52738414Smckusick } 52838414Smckusick 52938414Smckusick /* 53038414Smckusick * At this point, this should never happen 53138414Smckusick */ 53239494Smckusick /* ARGSUSED */ 53338414Smckusick nfs_fhtovp(mp, fhp, vpp) 53438414Smckusick struct mount *mp; 53538414Smckusick struct fid *fhp; 53638414Smckusick struct vnode **vpp; 53738414Smckusick { 53839494Smckusick 53938414Smckusick return (EINVAL); 54038414Smckusick } 54138414Smckusick 54238414Smckusick /* 54338414Smckusick * Vnode pointer to File handle, should never happen either 54438414Smckusick */ 54539494Smckusick /* ARGSUSED */ 54638414Smckusick nfs_vptofh(mp, fhp, vpp) 54738414Smckusick struct mount *mp; 54838414Smckusick struct fid *fhp; 54938414Smckusick struct vnode **vpp; 55038414Smckusick { 55139494Smckusick 55238414Smckusick return (EINVAL); 55338414Smckusick } 55438884Smacklem 55538884Smacklem /* 55638884Smacklem * Vfs start routine, a no-op. 55738884Smacklem */ 55839494Smckusick /* ARGSUSED */ 55938884Smacklem nfs_start(mp, flags) 56038884Smacklem struct mount *mp; 56138884Smacklem int flags; 56238884Smacklem { 56339494Smckusick 56438884Smacklem return (0); 56538884Smacklem } 56641294Smckusick 56741294Smckusick /* 56841294Smckusick * Do operations associated with quotas, not supported 56941294Smckusick */ 57041294Smckusick nfs_quotactl(mp, cmd, uid, arg) 57141294Smckusick struct mount *mp; 57241294Smckusick int cmd; 57341294Smckusick uid_t uid; 57441294Smckusick caddr_t arg; 57541294Smckusick { 57642245Smckusick #ifdef lint 57742245Smckusick mp = mp; cmd = cmd; uid = uid; arg = arg; 57842245Smckusick #endif /* lint */ 57941294Smckusick return (EOPNOTSUPP); 58041294Smckusick } 581