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*48055Smckusick * @(#)nfs_vfsops.c 7.27 (Berkeley) 04/16/91 1138414Smckusick */ 1238414Smckusick 1338414Smckusick #include "param.h" 1446988Smckusick #include "conf.h" 1546988Smckusick #include "ioctl.h" 1638414Smckusick #include "signal.h" 1738414Smckusick #include "proc.h" 18*48055Smckusick #include "namei.h" 1938414Smckusick #include "vnode.h" 2038414Smckusick #include "mount.h" 2140120Smckusick #include "buf.h" 2238414Smckusick #include "mbuf.h" 2338414Smckusick #include "socket.h" 2440120Smckusick #include "systm.h" 2547573Skarels 2646988Smckusick #include "../net/if.h" 2746988Smckusick #include "../net/route.h" 2846988Smckusick #include "../netinet/in.h" 2947573Skarels 3038414Smckusick #include "nfsv2.h" 3138414Smckusick #include "nfsnode.h" 3238414Smckusick #include "nfsmount.h" 3338414Smckusick #include "nfs.h" 3441904Smckusick #include "xdr_subs.h" 3541904Smckusick #include "nfsm_subs.h" 3646988Smckusick #include "nfsdiskless.h" 3738414Smckusick 3838414Smckusick /* 3938414Smckusick * nfs vfs operations. 4038414Smckusick */ 4138414Smckusick struct vfsops nfs_vfsops = { 4238414Smckusick nfs_mount, 4338874Smckusick nfs_start, 4438414Smckusick nfs_unmount, 4538414Smckusick nfs_root, 4641294Smckusick nfs_quotactl, 4738414Smckusick nfs_statfs, 4838414Smckusick nfs_sync, 4938414Smckusick nfs_fhtovp, 5038414Smckusick nfs_vptofh, 5139443Smckusick nfs_init, 5238414Smckusick }; 5338414Smckusick 5439757Smckusick static u_char nfs_mntid; 5541904Smckusick extern u_long nfs_procids[NFS_NPROCS]; 5641904Smckusick extern u_long nfs_prog, nfs_vers; 5746988Smckusick struct nfs_diskless nfs_diskless; 5841904Smckusick void nfs_disconnect(); 5938414Smckusick 6041904Smckusick #define TRUE 1 6141904Smckusick #define FALSE 0 6241904Smckusick 6338414Smckusick /* 6441904Smckusick * nfs statfs call 6541904Smckusick */ 66*48055Smckusick nfs_statfs(mp, sbp, p) 6741904Smckusick struct mount *mp; 6841904Smckusick register struct statfs *sbp; 69*48055Smckusick struct proc *p; 7041904Smckusick { 7141904Smckusick register struct vnode *vp; 7241904Smckusick register struct nfsv2_statfs *sfp; 7341904Smckusick register caddr_t cp; 7441904Smckusick register long t1; 7541904Smckusick caddr_t bpos, dpos, cp2; 7641904Smckusick u_long xid; 7741904Smckusick int error = 0; 7841904Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 7941904Smckusick struct nfsmount *nmp; 8041904Smckusick struct ucred *cred; 8141904Smckusick struct nfsnode *np; 8241904Smckusick 8341904Smckusick nmp = VFSTONFS(mp); 8441904Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 8541904Smckusick return (error); 8641904Smckusick vp = NFSTOV(np); 8741904Smckusick nfsstats.rpccnt[NFSPROC_STATFS]++; 8841904Smckusick cred = crget(); 8941904Smckusick cred->cr_ngroups = 1; 9041904Smckusick nfsm_reqhead(nfs_procids[NFSPROC_STATFS], cred, NFSX_FH); 9141904Smckusick nfsm_fhtom(vp); 92*48055Smckusick nfsm_request(vp, NFSPROC_STATFS, p, 0); 9341904Smckusick nfsm_disect(sfp, struct nfsv2_statfs *, NFSX_STATFS); 9441904Smckusick sbp->f_type = MOUNT_NFS; 9541904Smckusick sbp->f_flags = nmp->nm_flag; 9641904Smckusick sbp->f_bsize = fxdr_unsigned(long, sfp->sf_tsize); 9741904Smckusick sbp->f_fsize = fxdr_unsigned(long, sfp->sf_bsize); 9841904Smckusick sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks); 9941904Smckusick sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree); 10041904Smckusick sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail); 10141904Smckusick sbp->f_files = 0; 10241904Smckusick sbp->f_ffree = 0; 10341904Smckusick if (sbp != &mp->mnt_stat) { 10441904Smckusick bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 10541904Smckusick bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 10641904Smckusick } 10741904Smckusick nfsm_reqdone; 10841904Smckusick nfs_nput(vp); 10941904Smckusick crfree(cred); 11041904Smckusick return (error); 11141904Smckusick } 11241904Smckusick 11341904Smckusick /* 11446988Smckusick * Mount a remote root fs via. nfs. This depends on the info in the 11546988Smckusick * nfs_diskless structure that has been filled in properly by some primary 11646988Smckusick * bootstrap. 11746988Smckusick * It goes something like this: 11846988Smckusick * - do enough of "ifconfig" by calling ifioctl() so that the system 11946988Smckusick * can talk to the server 12046988Smckusick * - If nfs_diskless.mygateway is filled in, use that address as 12146988Smckusick * a default gateway. 12246988Smckusick * (This is done the 4.3 way with rtioctl() and should be changed) 12346988Smckusick * - hand craft the swap nfs vnode hanging off a fake mount point 12446988Smckusick * - build the rootfs mount point and call mountnfs() to do the rest. 12538414Smckusick */ 12638414Smckusick nfs_mountroot() 12738414Smckusick { 12846988Smckusick register struct mount *mp; 12946988Smckusick register struct mbuf *m; 13046988Smckusick struct socket *so; 13146988Smckusick struct vnode *vp; 13246988Smckusick int error; 13346988Smckusick 13446988Smckusick /* 13546988Smckusick * Do enough of ifconfig(8) so that critical net interface can 13646988Smckusick * talk to the server. 13746988Smckusick */ 13846988Smckusick if (socreate(nfs_diskless.myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0)) 13946988Smckusick panic("nfs ifconf"); 14046988Smckusick if (ifioctl(so, SIOCAIFADDR, &nfs_diskless.myif)) 14146988Smckusick panic("nfs ifconf2"); 14246988Smckusick soclose(so); 14346988Smckusick 14446988Smckusick /* 14546988Smckusick * If the gateway field is filled in, set it as the default route. 14646988Smckusick */ 14746988Smckusick #ifdef COMPAT_43 14846988Smckusick if (nfs_diskless.mygateway.sa_family == AF_INET) { 14946988Smckusick struct ortentry rt; 15046988Smckusick struct sockaddr_in *sin; 15146988Smckusick 15246988Smckusick sin = (struct sockaddr_in *) &rt.rt_dst; 15346988Smckusick sin->sin_len = sizeof (struct sockaddr_in); 15446988Smckusick sin->sin_family = AF_INET; 15546988Smckusick sin->sin_addr.s_addr = 0; /* default */ 15646988Smckusick bcopy((caddr_t)&nfs_diskless.mygateway, (caddr_t)&rt.rt_gateway, 15746988Smckusick sizeof (struct sockaddr_in)); 15846988Smckusick rt.rt_flags = (RTF_UP | RTF_GATEWAY); 15946988Smckusick if (rtioctl(SIOCADDRT, (caddr_t)&rt)) 16046988Smckusick panic("nfs root route"); 16146988Smckusick } 16246988Smckusick #endif /* COMPAT_43 */ 16346988Smckusick 16446988Smckusick /* 16546988Smckusick * If swapping to an nfs node (indicated by swdevt[0].sw_dev == NODEV): 16646988Smckusick * Create a fake mount point just for the swap vnode so that the 16746988Smckusick * swap file can be on a different server from the rootfs. 16846988Smckusick */ 16946988Smckusick if (swdevt[0].sw_dev == NODEV) { 17046988Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 17146988Smckusick M_MOUNT, M_NOWAIT); 17246988Smckusick if (mp == NULL) 17346988Smckusick panic("nfs root mount"); 17446988Smckusick mp->mnt_op = &nfs_vfsops; 17546988Smckusick mp->mnt_flag = 0; 17646988Smckusick mp->mnt_exroot = 0; 17746988Smckusick mp->mnt_mounth = NULLVP; 17846988Smckusick 17946988Smckusick /* 18046988Smckusick * Set up the diskless nfs_args for the swap mount point 18146988Smckusick * and then call mountnfs() to mount it. 18246988Smckusick * Since the swap file is not the root dir of a file system, 18346988Smckusick * hack it to a regular file. 18446988Smckusick */ 18546988Smckusick nfs_diskless.swap_args.fh = (nfsv2fh_t *)nfs_diskless.swap_fh; 18646988Smckusick MGET(m, MT_SONAME, M_DONTWAIT); 18746988Smckusick if (m == NULL) 18846988Smckusick panic("nfs root mbuf"); 18946988Smckusick bcopy((caddr_t)&nfs_diskless.swap_saddr, mtod(m, caddr_t), 19046988Smckusick nfs_diskless.swap_saddr.sa_len); 19146988Smckusick m->m_len = nfs_diskless.swap_saddr.sa_len; 19246988Smckusick if (mountnfs(&nfs_diskless.swap_args, mp, m, "/swap", 19346988Smckusick nfs_diskless.swap_hostnam, &vp)) 19446988Smckusick panic("nfs swap"); 19546988Smckusick vp->v_type = VREG; 19646988Smckusick vp->v_flag = 0; 19746988Smckusick swapdev_vp = vp; 19846988Smckusick VREF(vp); 19946988Smckusick swdevt[0].sw_vp = vp; 20046988Smckusick VREF(vp); 20146988Smckusick argdev_vp = vp; 20246988Smckusick } 20346988Smckusick 20446988Smckusick /* 20546988Smckusick * Create the rootfs mount point. 20646988Smckusick */ 20746988Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 20846988Smckusick M_MOUNT, M_NOWAIT); 20946988Smckusick if (mp == NULL) 21046988Smckusick panic("nfs root mount2"); 21146988Smckusick mp->mnt_op = &nfs_vfsops; 21246988Smckusick mp->mnt_flag = MNT_RDONLY; 21346988Smckusick mp->mnt_exroot = 0; 21446988Smckusick mp->mnt_mounth = NULLVP; 21546988Smckusick 21646988Smckusick /* 21746988Smckusick * Set up the root fs args and call mountnfs() to do the rest. 21846988Smckusick */ 21946988Smckusick nfs_diskless.root_args.fh = (nfsv2fh_t *)nfs_diskless.root_fh; 22046988Smckusick MGET(m, MT_SONAME, M_DONTWAIT); 22146988Smckusick if (m == NULL) 22246988Smckusick panic("nfs root mbuf2"); 22346988Smckusick bcopy((caddr_t)&nfs_diskless.root_saddr, mtod(m, caddr_t), 22446988Smckusick nfs_diskless.root_saddr.sa_len); 22546988Smckusick m->m_len = nfs_diskless.root_saddr.sa_len; 22646988Smckusick if (mountnfs(&nfs_diskless.root_args, mp, m, "/", 22746988Smckusick nfs_diskless.root_hostnam, &vp)) 22846988Smckusick panic("nfs root"); 22946988Smckusick if (vfs_lock(mp)) 23046988Smckusick panic("nfs root2"); 23146988Smckusick rootfs = mp; 23246988Smckusick mp->mnt_next = mp; 23346988Smckusick mp->mnt_prev = mp; 23446988Smckusick mp->mnt_vnodecovered = NULLVP; 23546988Smckusick vfs_unlock(mp); 23646988Smckusick rootvp = vp; 23746988Smckusick inittodr((time_t)0); /* There is no time in the nfs fsstat so ?? */ 23846988Smckusick return (0); 23938414Smckusick } 24038414Smckusick 24138414Smckusick /* 24238414Smckusick * VFS Operations. 24338414Smckusick * 24438414Smckusick * mount system call 24538414Smckusick * It seems a bit dumb to copyinstr() the host and path here and then 24638414Smckusick * bcopy() them in mountnfs(), but I wanted to detect errors before 24738414Smckusick * doing the sockargs() call because sockargs() allocates an mbuf and 24838414Smckusick * an error after that means that I have to release the mbuf. 24938414Smckusick */ 25039494Smckusick /* ARGSUSED */ 251*48055Smckusick nfs_mount(mp, path, data, ndp, p) 25238414Smckusick struct mount *mp; 25338414Smckusick char *path; 25438414Smckusick caddr_t data; 25538414Smckusick struct nameidata *ndp; 256*48055Smckusick struct proc *p; 25738414Smckusick { 25838414Smckusick int error; 25938414Smckusick struct nfs_args args; 26041904Smckusick struct mbuf *nam; 26146988Smckusick struct vnode *vp; 26238414Smckusick char pth[MNAMELEN], hst[MNAMELEN]; 26338414Smckusick int len; 26438414Smckusick nfsv2fh_t nfh; 26538414Smckusick 26641398Smckusick if (mp->mnt_flag & MNT_UPDATE) 26739460Smckusick return (0); 26838414Smckusick if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args))) 26938414Smckusick return (error); 27038414Smckusick if (error=copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t))) 27138414Smckusick return (error); 27238414Smckusick if (error = copyinstr(path, pth, MNAMELEN-1, &len)) 27338414Smckusick return (error); 27438414Smckusick bzero(&pth[len], MNAMELEN-len); 27538414Smckusick if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len)) 27638414Smckusick return (error); 27738414Smckusick bzero(&hst[len], MNAMELEN-len); 27838414Smckusick /* sockargs() call must be after above copyin() calls */ 27941904Smckusick if (error = sockargs(&nam, (caddr_t)args.addr, 28040120Smckusick sizeof (struct sockaddr), MT_SONAME)) 28138414Smckusick return (error); 28238414Smckusick args.fh = &nfh; 28346988Smckusick error = mountnfs(&args, mp, nam, pth, hst, &vp); 28438414Smckusick return (error); 28538414Smckusick } 28638414Smckusick 28738414Smckusick /* 28838414Smckusick * Common code for mount and mountroot 28938414Smckusick */ 29046988Smckusick mountnfs(argp, mp, nam, pth, hst, vpp) 29138414Smckusick register struct nfs_args *argp; 29238414Smckusick register struct mount *mp; 29341904Smckusick struct mbuf *nam; 29438414Smckusick char *pth, *hst; 29546988Smckusick struct vnode **vpp; 29638414Smckusick { 29738414Smckusick register struct nfsmount *nmp; 298*48055Smckusick struct proc *p = curproc; /* XXX */ 29940010Smckusick struct nfsnode *np; 30040120Smckusick int error; 30139757Smckusick fsid_t tfsid; 30238414Smckusick 30340120Smckusick MALLOC(nmp, struct nfsmount *, sizeof *nmp, M_NFSMNT, M_WAITOK); 30440120Smckusick bzero((caddr_t)nmp, sizeof *nmp); 30541398Smckusick mp->mnt_data = (qaddr_t)nmp; 30639757Smckusick /* 30739757Smckusick * Generate a unique nfs mount id. The problem is that a dev number 30839757Smckusick * is not unique across multiple systems. The techique is as follows: 30939757Smckusick * 1) Set to nblkdev,0 which will never be used otherwise 31039757Smckusick * 2) Generate a first guess as nblkdev,nfs_mntid where nfs_mntid is 31139757Smckusick * NOT 0 31239757Smckusick * 3) Loop searching the mount list for another one with same id 31339757Smckusick * If a match, increment val[0] and try again 31439757Smckusick * NB: I increment val[0] { a long } instead of nfs_mntid { a u_char } 31539757Smckusick * so that nfs is not limited to 255 mount points 31639757Smckusick * Incrementing the high order bits does no real harm, since it 31739757Smckusick * simply makes the major dev number tick up. The upper bound is 31839757Smckusick * set to major dev 127 to avoid any sign extention problems 31939757Smckusick */ 32041398Smckusick mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev, 0); 32141398Smckusick mp->mnt_stat.f_fsid.val[1] = MOUNT_NFS; 32239757Smckusick if (++nfs_mntid == 0) 32339757Smckusick ++nfs_mntid; 32439757Smckusick tfsid.val[0] = makedev(nblkdev, nfs_mntid); 32539757Smckusick tfsid.val[1] = MOUNT_NFS; 32646988Smckusick while (rootfs && getvfs(&tfsid)) { 32739757Smckusick tfsid.val[0]++; 32839757Smckusick nfs_mntid++; 32939757Smckusick } 33039757Smckusick if (major(tfsid.val[0]) > 127) { 33139757Smckusick error = ENOENT; 33239757Smckusick goto bad; 33339757Smckusick } 33441398Smckusick mp->mnt_stat.f_fsid.val[0] = tfsid.val[0]; 33538414Smckusick nmp->nm_mountp = mp; 33638414Smckusick nmp->nm_flag = argp->flags; 33740120Smckusick nmp->nm_rto = NFS_TIMEO; 33840120Smckusick nmp->nm_rtt = -1; 33940120Smckusick nmp->nm_rttvar = nmp->nm_rto << 1; 34040120Smckusick nmp->nm_retry = NFS_RETRANS; 34140120Smckusick nmp->nm_wsize = NFS_WSIZE; 34240120Smckusick nmp->nm_rsize = NFS_RSIZE; 34340120Smckusick bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t)); 34441398Smckusick mp->mnt_stat.f_type = MOUNT_NFS; 34541398Smckusick bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); 34641398Smckusick bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN); 34741904Smckusick nmp->nm_nam = nam; 34840120Smckusick 34940120Smckusick if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { 35040120Smckusick nmp->nm_rto = argp->timeo; 35140120Smckusick /* NFS timeouts are specified in 1/10 sec. */ 35240120Smckusick nmp->nm_rto = (nmp->nm_rto * 10) / NFS_HZ; 35340120Smckusick if (nmp->nm_rto < NFS_MINTIMEO) 35440120Smckusick nmp->nm_rto = NFS_MINTIMEO; 35540120Smckusick else if (nmp->nm_rto > NFS_MAXTIMEO) 35640120Smckusick nmp->nm_rto = NFS_MAXTIMEO; 35740120Smckusick nmp->nm_rttvar = nmp->nm_rto << 1; 35840120Smckusick } 35940120Smckusick 36043355Smckusick if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) { 36140120Smckusick nmp->nm_retry = argp->retrans; 36240120Smckusick if (nmp->nm_retry > NFS_MAXREXMIT) 36340120Smckusick nmp->nm_retry = NFS_MAXREXMIT; 36440120Smckusick } 36540120Smckusick 36640120Smckusick if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { 36738414Smckusick nmp->nm_wsize = argp->wsize; 36840120Smckusick /* Round down to multiple of blocksize */ 36940120Smckusick nmp->nm_wsize &= ~0x1ff; 37040120Smckusick if (nmp->nm_wsize <= 0) 37140120Smckusick nmp->nm_wsize = 512; 37240120Smckusick else if (nmp->nm_wsize > NFS_MAXDATA) 37340120Smckusick nmp->nm_wsize = NFS_MAXDATA; 37440120Smckusick } 37543355Smckusick if (nmp->nm_wsize > MAXBSIZE) 37643355Smckusick nmp->nm_wsize = MAXBSIZE; 37740120Smckusick 37840120Smckusick if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { 37938414Smckusick nmp->nm_rsize = argp->rsize; 38040120Smckusick /* Round down to multiple of blocksize */ 38140120Smckusick nmp->nm_rsize &= ~0x1ff; 38240120Smckusick if (nmp->nm_rsize <= 0) 38340120Smckusick nmp->nm_rsize = 512; 38440120Smckusick else if (nmp->nm_rsize > NFS_MAXDATA) 38540120Smckusick nmp->nm_rsize = NFS_MAXDATA; 38640120Smckusick } 38743355Smckusick if (nmp->nm_rsize > MAXBSIZE) 38843355Smckusick nmp->nm_rsize = MAXBSIZE; 38940120Smckusick /* Set up the sockets and per-host congestion */ 39041904Smckusick nmp->nm_sotype = argp->sotype; 39141904Smckusick nmp->nm_soproto = argp->proto; 39241904Smckusick if (error = nfs_connect(nmp)) 39340120Smckusick goto bad; 39440120Smckusick 395*48055Smckusick if (error = nfs_statfs(mp, &mp->mnt_stat, p)) 39640353Smckusick goto bad; 39738414Smckusick /* 39840010Smckusick * A reference count is needed on the nfsnode representing the 39940010Smckusick * remote root. If this object is not persistent, then backward 40040010Smckusick * traversals of the mount point (i.e. "..") will not work if 40140010Smckusick * the nfsnode gets flushed out of the cache. Ufs does not have 40240010Smckusick * this problem, because one can identify root inodes by their 40340010Smckusick * number == ROOTINO (2). 40440010Smckusick */ 40540010Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 40640010Smckusick goto bad; 40740010Smckusick /* 40840010Smckusick * Unlock it, but keep the reference count. 40940010Smckusick */ 41040010Smckusick nfs_unlock(NFSTOV(np)); 41146988Smckusick *vpp = NFSTOV(np); 41241904Smckusick 41340353Smckusick return (0); 41438414Smckusick bad: 41540120Smckusick nfs_disconnect(nmp); 41640120Smckusick FREE(nmp, M_NFSMNT); 41741904Smckusick m_freem(nam); 41838414Smckusick return (error); 41938414Smckusick } 42038414Smckusick 42138414Smckusick /* 42238414Smckusick * unmount system call 42338414Smckusick */ 424*48055Smckusick nfs_unmount(mp, mntflags, p) 42538414Smckusick struct mount *mp; 42641294Smckusick int mntflags; 427*48055Smckusick struct proc *p; 42838414Smckusick { 42938414Smckusick register struct nfsmount *nmp; 43040010Smckusick struct nfsnode *np; 43140120Smckusick struct vnode *vp; 43241294Smckusick int flags = 0; 43338414Smckusick int error; 43438414Smckusick 43541294Smckusick if (mntflags & MNT_FORCE) 43638414Smckusick return (EINVAL); 43741294Smckusick if (mntflags & MNT_FORCE) 43841294Smckusick flags |= FORCECLOSE; 43941398Smckusick nmp = VFSTONFS(mp); 44038414Smckusick /* 44138884Smacklem * Clear out the buffer cache 44238884Smacklem */ 44339669Smckusick mntflushbuf(mp, 0); 44439669Smckusick if (mntinvalbuf(mp)) 44538884Smacklem return (EBUSY); 44638884Smacklem /* 44738414Smckusick * Goes something like this.. 44840120Smckusick * - Check for activity on the root vnode (other than ourselves). 44940120Smckusick * - Call vflush() to clear out vnodes for this file system, 45040120Smckusick * except for the root vnode. 45140120Smckusick * - Decrement reference on the vnode representing remote root. 45238414Smckusick * - Close the socket 45338414Smckusick * - Free up the data structures 45438414Smckusick */ 45540010Smckusick /* 45640010Smckusick * We need to decrement the ref. count on the nfsnode representing 45740010Smckusick * the remote root. See comment in mountnfs(). The VFS unmount() 45840010Smckusick * has done vput on this vnode, otherwise we would get deadlock! 45940010Smckusick */ 46040010Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 46140010Smckusick return(error); 46240120Smckusick vp = NFSTOV(np); 46340120Smckusick if (vp->v_usecount > 2) { 46440120Smckusick vput(vp); 46540120Smckusick return (EBUSY); 46640120Smckusick } 46740120Smckusick if (error = vflush(mp, vp, flags)) { 46840120Smckusick vput(vp); 46940120Smckusick return (error); 47040120Smckusick } 47140010Smckusick /* 47240010Smckusick * Get rid of two reference counts, and unlock it on the second. 47340010Smckusick */ 47440120Smckusick vrele(vp); 47540120Smckusick vput(vp); 47640120Smckusick nfs_disconnect(nmp); 47741904Smckusick m_freem(nmp->nm_nam); 47838414Smckusick free((caddr_t)nmp, M_NFSMNT); 47938414Smckusick return (0); 48038414Smckusick } 48138414Smckusick 48238414Smckusick /* 48338414Smckusick * Return root of a filesystem 48438414Smckusick */ 48538414Smckusick nfs_root(mp, vpp) 48638414Smckusick struct mount *mp; 48738414Smckusick struct vnode **vpp; 48838414Smckusick { 48938414Smckusick register struct vnode *vp; 49038414Smckusick struct nfsmount *nmp; 49138414Smckusick struct nfsnode *np; 49238414Smckusick int error; 49338414Smckusick 49441398Smckusick nmp = VFSTONFS(mp); 49538414Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 49638414Smckusick return (error); 49738414Smckusick vp = NFSTOV(np); 49838414Smckusick vp->v_type = VDIR; 49938414Smckusick vp->v_flag = VROOT; 50038414Smckusick *vpp = vp; 50138414Smckusick return (0); 50238414Smckusick } 50338414Smckusick 50438884Smacklem extern int syncprt; 50538884Smacklem 50638414Smckusick /* 50738884Smacklem * Flush out the buffer cache 50838414Smckusick */ 50939494Smckusick /* ARGSUSED */ 51038414Smckusick nfs_sync(mp, waitfor) 51138414Smckusick struct mount *mp; 51238414Smckusick int waitfor; 51338414Smckusick { 51438884Smacklem if (syncprt) 51538884Smacklem bufstats(); 51638884Smacklem /* 51738884Smacklem * Force stale buffer cache information to be flushed. 51838884Smacklem */ 51940035Smckusick mntflushbuf(mp, waitfor == MNT_WAIT ? B_SYNC : 0); 52038414Smckusick return (0); 52138414Smckusick } 52238414Smckusick 52338414Smckusick /* 52438414Smckusick * At this point, this should never happen 52538414Smckusick */ 52639494Smckusick /* ARGSUSED */ 52738414Smckusick nfs_fhtovp(mp, fhp, vpp) 52838414Smckusick struct mount *mp; 52938414Smckusick struct fid *fhp; 53038414Smckusick struct vnode **vpp; 53138414Smckusick { 53239494Smckusick 53338414Smckusick return (EINVAL); 53438414Smckusick } 53538414Smckusick 53638414Smckusick /* 53738414Smckusick * Vnode pointer to File handle, should never happen either 53838414Smckusick */ 53939494Smckusick /* ARGSUSED */ 540*48055Smckusick nfs_vptofh(vp, fhp) 541*48055Smckusick struct vnode *vp; 54238414Smckusick struct fid *fhp; 54338414Smckusick { 54439494Smckusick 54538414Smckusick return (EINVAL); 54638414Smckusick } 54738884Smacklem 54838884Smacklem /* 54938884Smacklem * Vfs start routine, a no-op. 55038884Smacklem */ 55139494Smckusick /* ARGSUSED */ 552*48055Smckusick nfs_start(mp, flags, p) 55338884Smacklem struct mount *mp; 55438884Smacklem int flags; 555*48055Smckusick struct proc *p; 55638884Smacklem { 55739494Smckusick 55838884Smacklem return (0); 55938884Smacklem } 56041294Smckusick 56141294Smckusick /* 56241294Smckusick * Do operations associated with quotas, not supported 56341294Smckusick */ 564*48055Smckusick nfs_quotactl(mp, cmd, uid, arg, p) 56541294Smckusick struct mount *mp; 56641294Smckusick int cmd; 56741294Smckusick uid_t uid; 56841294Smckusick caddr_t arg; 569*48055Smckusick struct proc *p; 57041294Smckusick { 57142245Smckusick #ifdef lint 57242245Smckusick mp = mp; cmd = cmd; uid = uid; arg = arg; 57342245Smckusick #endif /* lint */ 57441294Smckusick return (EOPNOTSUPP); 57541294Smckusick } 576