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*51574Smckusick * @(#)nfs_vfsops.c 7.33 (Berkeley) 11/05/91 1138414Smckusick */ 1238414Smckusick 1338414Smckusick #include "param.h" 1446988Smckusick #include "conf.h" 1546988Smckusick #include "ioctl.h" 1638414Smckusick #include "signal.h" 1738414Smckusick #include "proc.h" 1848055Smckusick #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 */ 6648055Smckusick nfs_statfs(mp, sbp, p) 6741904Smckusick struct mount *mp; 6841904Smckusick register struct statfs *sbp; 6948055Smckusick 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); 9248055Smckusick 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 } 20146988Smckusick 20246988Smckusick /* 20346988Smckusick * Create the rootfs mount point. 20446988Smckusick */ 20546988Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 20646988Smckusick M_MOUNT, M_NOWAIT); 20746988Smckusick if (mp == NULL) 20846988Smckusick panic("nfs root mount2"); 20946988Smckusick mp->mnt_op = &nfs_vfsops; 21046988Smckusick mp->mnt_flag = MNT_RDONLY; 21146988Smckusick mp->mnt_exroot = 0; 21246988Smckusick mp->mnt_mounth = NULLVP; 21346988Smckusick 21446988Smckusick /* 21546988Smckusick * Set up the root fs args and call mountnfs() to do the rest. 21646988Smckusick */ 21746988Smckusick nfs_diskless.root_args.fh = (nfsv2fh_t *)nfs_diskless.root_fh; 21846988Smckusick MGET(m, MT_SONAME, M_DONTWAIT); 21946988Smckusick if (m == NULL) 22046988Smckusick panic("nfs root mbuf2"); 22146988Smckusick bcopy((caddr_t)&nfs_diskless.root_saddr, mtod(m, caddr_t), 22246988Smckusick nfs_diskless.root_saddr.sa_len); 22346988Smckusick m->m_len = nfs_diskless.root_saddr.sa_len; 22446988Smckusick if (mountnfs(&nfs_diskless.root_args, mp, m, "/", 22546988Smckusick nfs_diskless.root_hostnam, &vp)) 22646988Smckusick panic("nfs root"); 22746988Smckusick if (vfs_lock(mp)) 22846988Smckusick panic("nfs root2"); 22946988Smckusick rootfs = mp; 23046988Smckusick mp->mnt_next = mp; 23146988Smckusick mp->mnt_prev = mp; 23246988Smckusick mp->mnt_vnodecovered = NULLVP; 23346988Smckusick vfs_unlock(mp); 23446988Smckusick rootvp = vp; 23546988Smckusick inittodr((time_t)0); /* There is no time in the nfs fsstat so ?? */ 23646988Smckusick return (0); 23738414Smckusick } 23838414Smckusick 23938414Smckusick /* 24038414Smckusick * VFS Operations. 24138414Smckusick * 24238414Smckusick * mount system call 24338414Smckusick * It seems a bit dumb to copyinstr() the host and path here and then 24438414Smckusick * bcopy() them in mountnfs(), but I wanted to detect errors before 24538414Smckusick * doing the sockargs() call because sockargs() allocates an mbuf and 24638414Smckusick * an error after that means that I have to release the mbuf. 24738414Smckusick */ 24839494Smckusick /* ARGSUSED */ 24948055Smckusick nfs_mount(mp, path, data, ndp, p) 25038414Smckusick struct mount *mp; 25138414Smckusick char *path; 25238414Smckusick caddr_t data; 25338414Smckusick struct nameidata *ndp; 25448055Smckusick struct proc *p; 25538414Smckusick { 25638414Smckusick int error; 25738414Smckusick struct nfs_args args; 25841904Smckusick struct mbuf *nam; 25946988Smckusick struct vnode *vp; 26038414Smckusick char pth[MNAMELEN], hst[MNAMELEN]; 26149108Skarels u_int len; 26238414Smckusick nfsv2fh_t nfh; 26338414Smckusick 26441398Smckusick if (mp->mnt_flag & MNT_UPDATE) 26539460Smckusick return (0); 26638414Smckusick if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args))) 26738414Smckusick return (error); 26849108Skarels if (error = copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t))) 26938414Smckusick return (error); 27038414Smckusick if (error = copyinstr(path, pth, MNAMELEN-1, &len)) 27138414Smckusick return (error); 27249108Skarels bzero(&pth[len], MNAMELEN - len); 27338414Smckusick if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len)) 27438414Smckusick return (error); 27549108Skarels bzero(&hst[len], MNAMELEN - len); 27638414Smckusick /* sockargs() call must be after above copyin() calls */ 27741904Smckusick if (error = sockargs(&nam, (caddr_t)args.addr, 27840120Smckusick sizeof (struct sockaddr), MT_SONAME)) 27938414Smckusick return (error); 28038414Smckusick args.fh = &nfh; 28146988Smckusick error = mountnfs(&args, mp, nam, pth, hst, &vp); 28238414Smckusick return (error); 28338414Smckusick } 28438414Smckusick 28538414Smckusick /* 28638414Smckusick * Common code for mount and mountroot 28738414Smckusick */ 28846988Smckusick mountnfs(argp, mp, nam, pth, hst, vpp) 28938414Smckusick register struct nfs_args *argp; 29038414Smckusick register struct mount *mp; 29141904Smckusick struct mbuf *nam; 29238414Smckusick char *pth, *hst; 29346988Smckusick struct vnode **vpp; 29438414Smckusick { 29538414Smckusick register struct nfsmount *nmp; 29648055Smckusick struct proc *p = curproc; /* XXX */ 29740010Smckusick struct nfsnode *np; 29840120Smckusick int error; 29939757Smckusick fsid_t tfsid; 30038414Smckusick 30140120Smckusick MALLOC(nmp, struct nfsmount *, sizeof *nmp, M_NFSMNT, M_WAITOK); 30240120Smckusick bzero((caddr_t)nmp, sizeof *nmp); 30341398Smckusick mp->mnt_data = (qaddr_t)nmp; 30439757Smckusick /* 30539757Smckusick * Generate a unique nfs mount id. The problem is that a dev number 30639757Smckusick * is not unique across multiple systems. The techique is as follows: 30739757Smckusick * 1) Set to nblkdev,0 which will never be used otherwise 30839757Smckusick * 2) Generate a first guess as nblkdev,nfs_mntid where nfs_mntid is 30939757Smckusick * NOT 0 31039757Smckusick * 3) Loop searching the mount list for another one with same id 31139757Smckusick * If a match, increment val[0] and try again 31239757Smckusick * NB: I increment val[0] { a long } instead of nfs_mntid { a u_char } 31339757Smckusick * so that nfs is not limited to 255 mount points 31439757Smckusick * Incrementing the high order bits does no real harm, since it 31539757Smckusick * simply makes the major dev number tick up. The upper bound is 31639757Smckusick * set to major dev 127 to avoid any sign extention problems 31739757Smckusick */ 31841398Smckusick mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev, 0); 31941398Smckusick mp->mnt_stat.f_fsid.val[1] = MOUNT_NFS; 32039757Smckusick if (++nfs_mntid == 0) 32139757Smckusick ++nfs_mntid; 32239757Smckusick tfsid.val[0] = makedev(nblkdev, nfs_mntid); 32339757Smckusick tfsid.val[1] = MOUNT_NFS; 32446988Smckusick while (rootfs && getvfs(&tfsid)) { 32539757Smckusick tfsid.val[0]++; 32639757Smckusick nfs_mntid++; 32739757Smckusick } 32839757Smckusick if (major(tfsid.val[0]) > 127) { 32939757Smckusick error = ENOENT; 33039757Smckusick goto bad; 33139757Smckusick } 33241398Smckusick mp->mnt_stat.f_fsid.val[0] = tfsid.val[0]; 33338414Smckusick nmp->nm_mountp = mp; 33438414Smckusick nmp->nm_flag = argp->flags; 33540120Smckusick nmp->nm_rto = NFS_TIMEO; 33640120Smckusick nmp->nm_rtt = -1; 33740120Smckusick nmp->nm_rttvar = nmp->nm_rto << 1; 33840120Smckusick nmp->nm_retry = NFS_RETRANS; 33940120Smckusick nmp->nm_wsize = NFS_WSIZE; 34040120Smckusick nmp->nm_rsize = NFS_RSIZE; 34140120Smckusick bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t)); 34241398Smckusick mp->mnt_stat.f_type = MOUNT_NFS; 34341398Smckusick bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); 34441398Smckusick bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN); 34541904Smckusick nmp->nm_nam = nam; 34640120Smckusick 34740120Smckusick if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { 34840120Smckusick nmp->nm_rto = argp->timeo; 34940120Smckusick /* NFS timeouts are specified in 1/10 sec. */ 35040120Smckusick nmp->nm_rto = (nmp->nm_rto * 10) / NFS_HZ; 35140120Smckusick if (nmp->nm_rto < NFS_MINTIMEO) 35240120Smckusick nmp->nm_rto = NFS_MINTIMEO; 35340120Smckusick else if (nmp->nm_rto > NFS_MAXTIMEO) 35440120Smckusick nmp->nm_rto = NFS_MAXTIMEO; 35540120Smckusick nmp->nm_rttvar = nmp->nm_rto << 1; 35640120Smckusick } 35740120Smckusick 35843355Smckusick if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) { 35940120Smckusick nmp->nm_retry = argp->retrans; 36040120Smckusick if (nmp->nm_retry > NFS_MAXREXMIT) 36140120Smckusick nmp->nm_retry = NFS_MAXREXMIT; 36240120Smckusick } 36340120Smckusick 36440120Smckusick if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { 36538414Smckusick nmp->nm_wsize = argp->wsize; 36640120Smckusick /* Round down to multiple of blocksize */ 36740120Smckusick nmp->nm_wsize &= ~0x1ff; 36840120Smckusick if (nmp->nm_wsize <= 0) 36940120Smckusick nmp->nm_wsize = 512; 37040120Smckusick else if (nmp->nm_wsize > NFS_MAXDATA) 37140120Smckusick nmp->nm_wsize = NFS_MAXDATA; 37240120Smckusick } 37343355Smckusick if (nmp->nm_wsize > MAXBSIZE) 37443355Smckusick nmp->nm_wsize = MAXBSIZE; 37540120Smckusick 37640120Smckusick if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { 37738414Smckusick nmp->nm_rsize = argp->rsize; 37840120Smckusick /* Round down to multiple of blocksize */ 37940120Smckusick nmp->nm_rsize &= ~0x1ff; 38040120Smckusick if (nmp->nm_rsize <= 0) 38140120Smckusick nmp->nm_rsize = 512; 38240120Smckusick else if (nmp->nm_rsize > NFS_MAXDATA) 38340120Smckusick nmp->nm_rsize = NFS_MAXDATA; 38440120Smckusick } 38543355Smckusick if (nmp->nm_rsize > MAXBSIZE) 38643355Smckusick nmp->nm_rsize = MAXBSIZE; 38740120Smckusick /* Set up the sockets and per-host congestion */ 38841904Smckusick nmp->nm_sotype = argp->sotype; 38941904Smckusick nmp->nm_soproto = argp->proto; 39041904Smckusick if (error = nfs_connect(nmp)) 39140120Smckusick goto bad; 39240120Smckusick 39348055Smckusick if (error = nfs_statfs(mp, &mp->mnt_stat, p)) 39440353Smckusick goto bad; 39538414Smckusick /* 39640010Smckusick * A reference count is needed on the nfsnode representing the 39740010Smckusick * remote root. If this object is not persistent, then backward 39840010Smckusick * traversals of the mount point (i.e. "..") will not work if 39940010Smckusick * the nfsnode gets flushed out of the cache. Ufs does not have 40040010Smckusick * this problem, because one can identify root inodes by their 40140010Smckusick * number == ROOTINO (2). 40240010Smckusick */ 40340010Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 40440010Smckusick goto bad; 40540010Smckusick /* 40640010Smckusick * Unlock it, but keep the reference count. 40740010Smckusick */ 40840010Smckusick nfs_unlock(NFSTOV(np)); 40946988Smckusick *vpp = NFSTOV(np); 41041904Smckusick 41140353Smckusick return (0); 41238414Smckusick bad: 41340120Smckusick nfs_disconnect(nmp); 41440120Smckusick FREE(nmp, M_NFSMNT); 41541904Smckusick m_freem(nam); 41638414Smckusick return (error); 41738414Smckusick } 41838414Smckusick 41938414Smckusick /* 42038414Smckusick * unmount system call 42138414Smckusick */ 42248055Smckusick nfs_unmount(mp, mntflags, p) 42338414Smckusick struct mount *mp; 42441294Smckusick int mntflags; 42548055Smckusick struct proc *p; 42638414Smckusick { 42738414Smckusick register struct nfsmount *nmp; 42840010Smckusick struct nfsnode *np; 42940120Smckusick struct vnode *vp; 43048361Smckusick int error, flags = 0; 43148361Smckusick extern int doforce; 43238414Smckusick 43348066Smckusick if (mntflags & MNT_FORCE) { 43448361Smckusick if (!doforce || mp == rootfs) 43548066Smckusick return (EINVAL); 43641294Smckusick flags |= FORCECLOSE; 43748066Smckusick } 43841398Smckusick nmp = VFSTONFS(mp); 43938414Smckusick /* 44038884Smacklem * Clear out the buffer cache 44138884Smacklem */ 44239669Smckusick mntflushbuf(mp, 0); 44339669Smckusick if (mntinvalbuf(mp)) 44438884Smacklem return (EBUSY); 44538884Smacklem /* 44638414Smckusick * Goes something like this.. 44740120Smckusick * - Check for activity on the root vnode (other than ourselves). 44840120Smckusick * - Call vflush() to clear out vnodes for this file system, 44940120Smckusick * except for the root vnode. 45040120Smckusick * - Decrement reference on the vnode representing remote root. 45138414Smckusick * - Close the socket 45238414Smckusick * - Free up the data structures 45338414Smckusick */ 45440010Smckusick /* 45540010Smckusick * We need to decrement the ref. count on the nfsnode representing 45640010Smckusick * the remote root. See comment in mountnfs(). The VFS unmount() 45740010Smckusick * has done vput on this vnode, otherwise we would get deadlock! 45840010Smckusick */ 45940010Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 46040010Smckusick return(error); 46140120Smckusick vp = NFSTOV(np); 46240120Smckusick if (vp->v_usecount > 2) { 46340120Smckusick vput(vp); 46440120Smckusick return (EBUSY); 46540120Smckusick } 46640120Smckusick if (error = vflush(mp, vp, flags)) { 46740120Smckusick vput(vp); 46840120Smckusick return (error); 46940120Smckusick } 47040010Smckusick /* 47140010Smckusick * Get rid of two reference counts, and unlock it on the second. 47240010Smckusick */ 47340120Smckusick vrele(vp); 47440120Smckusick vput(vp); 47540120Smckusick nfs_disconnect(nmp); 47641904Smckusick m_freem(nmp->nm_nam); 47738414Smckusick free((caddr_t)nmp, M_NFSMNT); 47838414Smckusick return (0); 47938414Smckusick } 48038414Smckusick 48138414Smckusick /* 48238414Smckusick * Return root of a filesystem 48338414Smckusick */ 48438414Smckusick nfs_root(mp, vpp) 48538414Smckusick struct mount *mp; 48638414Smckusick struct vnode **vpp; 48738414Smckusick { 48838414Smckusick register struct vnode *vp; 48938414Smckusick struct nfsmount *nmp; 49038414Smckusick struct nfsnode *np; 49138414Smckusick int error; 49238414Smckusick 49341398Smckusick nmp = VFSTONFS(mp); 49438414Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 49538414Smckusick return (error); 49638414Smckusick vp = NFSTOV(np); 49738414Smckusick vp->v_type = VDIR; 49838414Smckusick vp->v_flag = VROOT; 49938414Smckusick *vpp = vp; 50038414Smckusick return (0); 50138414Smckusick } 50238414Smckusick 50338884Smacklem extern int syncprt; 50438884Smacklem 50538414Smckusick /* 50638884Smacklem * Flush out the buffer cache 50738414Smckusick */ 50839494Smckusick /* ARGSUSED */ 50938414Smckusick nfs_sync(mp, waitfor) 51038414Smckusick struct mount *mp; 51138414Smckusick int waitfor; 51238414Smckusick { 51338884Smacklem if (syncprt) 51451465Sbostic ufs_bufstats(); 51538884Smacklem /* 51638884Smacklem * Force stale buffer cache information to be flushed. 51738884Smacklem */ 51840035Smckusick mntflushbuf(mp, waitfor == MNT_WAIT ? B_SYNC : 0); 51938414Smckusick return (0); 52038414Smckusick } 52138414Smckusick 52238414Smckusick /* 52338414Smckusick * At this point, this should never happen 52438414Smckusick */ 52539494Smckusick /* ARGSUSED */ 52638414Smckusick nfs_fhtovp(mp, fhp, vpp) 52738414Smckusick struct mount *mp; 52838414Smckusick struct fid *fhp; 52938414Smckusick struct vnode **vpp; 53038414Smckusick { 53139494Smckusick 53238414Smckusick return (EINVAL); 53338414Smckusick } 53438414Smckusick 53538414Smckusick /* 53638414Smckusick * Vnode pointer to File handle, should never happen either 53738414Smckusick */ 53839494Smckusick /* ARGSUSED */ 53948055Smckusick nfs_vptofh(vp, fhp) 54048055Smckusick struct vnode *vp; 54138414Smckusick struct fid *fhp; 54238414Smckusick { 54339494Smckusick 54438414Smckusick return (EINVAL); 54538414Smckusick } 54638884Smacklem 54738884Smacklem /* 54838884Smacklem * Vfs start routine, a no-op. 54938884Smacklem */ 55039494Smckusick /* ARGSUSED */ 55148055Smckusick nfs_start(mp, flags, p) 55238884Smacklem struct mount *mp; 55338884Smacklem int flags; 55448055Smckusick struct proc *p; 55538884Smacklem { 55639494Smckusick 55738884Smacklem return (0); 55838884Smacklem } 55941294Smckusick 56041294Smckusick /* 56141294Smckusick * Do operations associated with quotas, not supported 56241294Smckusick */ 563*51574Smckusick /* ARGSUSED */ 56448055Smckusick nfs_quotactl(mp, cmd, uid, arg, p) 56541294Smckusick struct mount *mp; 56641294Smckusick int cmd; 567*51574Smckusick u_int uid; 56841294Smckusick caddr_t arg; 56948055Smckusick struct proc *p; 57041294Smckusick { 571*51574Smckusick 57241294Smckusick return (EOPNOTSUPP); 57341294Smckusick } 574