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 * 8*44513Sbostic * %sccs.include.redist.c% 938414Smckusick * 10*44513Sbostic * @(#)nfs_vfsops.c 7.24 (Berkeley) 06/28/90 1138414Smckusick */ 1238414Smckusick 1338414Smckusick #include "param.h" 1438414Smckusick #include "signal.h" 1538414Smckusick #include "user.h" 1638414Smckusick #include "proc.h" 1738414Smckusick #include "vnode.h" 1838414Smckusick #include "mount.h" 1938414Smckusick #include "errno.h" 2040120Smckusick #include "buf.h" 2138414Smckusick #include "mbuf.h" 2238414Smckusick #include "socket.h" 2340120Smckusick #include "systm.h" 2438414Smckusick #include "nfsv2.h" 2538414Smckusick #include "nfsnode.h" 2638414Smckusick #include "nfsmount.h" 2738414Smckusick #include "nfs.h" 2841904Smckusick #include "xdr_subs.h" 2941904Smckusick #include "nfsm_subs.h" 3038414Smckusick 3138414Smckusick /* 3238414Smckusick * nfs vfs operations. 3338414Smckusick */ 3438414Smckusick int nfs_mount(); 3538874Smckusick int nfs_start(); 3638414Smckusick int nfs_unmount(); 3738414Smckusick int nfs_root(); 3841294Smckusick int nfs_quotactl(); 3939443Smckusick int nfs_statfs(); 4038414Smckusick int nfs_sync(); 4138414Smckusick int nfs_fhtovp(); 4238414Smckusick int nfs_vptofh(); 4339443Smckusick int nfs_init(); 4438414Smckusick 4538414Smckusick struct vfsops nfs_vfsops = { 4638414Smckusick nfs_mount, 4738874Smckusick nfs_start, 4838414Smckusick nfs_unmount, 4938414Smckusick nfs_root, 5041294Smckusick nfs_quotactl, 5138414Smckusick nfs_statfs, 5238414Smckusick nfs_sync, 5338414Smckusick nfs_fhtovp, 5438414Smckusick nfs_vptofh, 5539443Smckusick nfs_init, 5638414Smckusick }; 5738414Smckusick 5839757Smckusick static u_char nfs_mntid; 5941904Smckusick extern u_long nfs_procids[NFS_NPROCS]; 6041904Smckusick extern u_long nfs_prog, nfs_vers; 6141904Smckusick void nfs_disconnect(); 6238414Smckusick 6341904Smckusick #define TRUE 1 6441904Smckusick #define FALSE 0 6541904Smckusick 6638414Smckusick /* 6741904Smckusick * nfs statfs call 6841904Smckusick */ 6941904Smckusick nfs_statfs(mp, sbp) 7041904Smckusick struct mount *mp; 7141904Smckusick register struct statfs *sbp; 7241904Smckusick { 7341904Smckusick register struct vnode *vp; 7441904Smckusick register struct nfsv2_statfs *sfp; 7541904Smckusick register caddr_t cp; 7641904Smckusick register long t1; 7741904Smckusick caddr_t bpos, dpos, cp2; 7841904Smckusick u_long xid; 7941904Smckusick int error = 0; 8041904Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 8141904Smckusick struct nfsmount *nmp; 8241904Smckusick struct ucred *cred; 8341904Smckusick struct nfsnode *np; 8441904Smckusick 8541904Smckusick nmp = VFSTONFS(mp); 8641904Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 8741904Smckusick return (error); 8841904Smckusick vp = NFSTOV(np); 8941904Smckusick nfsstats.rpccnt[NFSPROC_STATFS]++; 9041904Smckusick cred = crget(); 9141904Smckusick cred->cr_ngroups = 1; 9241904Smckusick nfsm_reqhead(nfs_procids[NFSPROC_STATFS], cred, NFSX_FH); 9341904Smckusick nfsm_fhtom(vp); 9443355Smckusick nfsm_request(vp, NFSPROC_STATFS, u.u_procp, 0); 9541904Smckusick nfsm_disect(sfp, struct nfsv2_statfs *, NFSX_STATFS); 9641904Smckusick sbp->f_type = MOUNT_NFS; 9741904Smckusick sbp->f_flags = nmp->nm_flag; 9841904Smckusick sbp->f_bsize = fxdr_unsigned(long, sfp->sf_tsize); 9941904Smckusick sbp->f_fsize = fxdr_unsigned(long, sfp->sf_bsize); 10041904Smckusick sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks); 10141904Smckusick sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree); 10241904Smckusick sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail); 10341904Smckusick sbp->f_files = 0; 10441904Smckusick sbp->f_ffree = 0; 10541904Smckusick if (sbp != &mp->mnt_stat) { 10641904Smckusick bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 10741904Smckusick bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 10841904Smckusick } 10941904Smckusick nfsm_reqdone; 11041904Smckusick nfs_nput(vp); 11141904Smckusick crfree(cred); 11241904Smckusick return (error); 11341904Smckusick } 11441904Smckusick 11541904Smckusick /* 11638414Smckusick * Called by vfs_mountroot when nfs is going to be mounted as root 11738414Smckusick * Not Yet (By a LONG shot) 11838414Smckusick */ 11938414Smckusick nfs_mountroot() 12038414Smckusick { 12138414Smckusick return (ENODEV); 12238414Smckusick } 12338414Smckusick 12438414Smckusick /* 12538414Smckusick * VFS Operations. 12638414Smckusick * 12738414Smckusick * mount system call 12838414Smckusick * It seems a bit dumb to copyinstr() the host and path here and then 12938414Smckusick * bcopy() them in mountnfs(), but I wanted to detect errors before 13038414Smckusick * doing the sockargs() call because sockargs() allocates an mbuf and 13138414Smckusick * an error after that means that I have to release the mbuf. 13238414Smckusick */ 13339494Smckusick /* ARGSUSED */ 13438414Smckusick nfs_mount(mp, path, data, ndp) 13538414Smckusick struct mount *mp; 13638414Smckusick char *path; 13738414Smckusick caddr_t data; 13838414Smckusick struct nameidata *ndp; 13938414Smckusick { 14038414Smckusick int error; 14138414Smckusick struct nfs_args args; 14241904Smckusick struct mbuf *nam; 14338414Smckusick char pth[MNAMELEN], hst[MNAMELEN]; 14438414Smckusick int len; 14538414Smckusick nfsv2fh_t nfh; 14638414Smckusick 14741398Smckusick if (mp->mnt_flag & MNT_UPDATE) 14839460Smckusick return (0); 14938414Smckusick if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args))) 15038414Smckusick return (error); 15138414Smckusick if (error=copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t))) 15238414Smckusick return (error); 15338414Smckusick if (error = copyinstr(path, pth, MNAMELEN-1, &len)) 15438414Smckusick return (error); 15538414Smckusick bzero(&pth[len], MNAMELEN-len); 15638414Smckusick if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len)) 15738414Smckusick return (error); 15838414Smckusick bzero(&hst[len], MNAMELEN-len); 15938414Smckusick /* sockargs() call must be after above copyin() calls */ 16041904Smckusick if (error = sockargs(&nam, (caddr_t)args.addr, 16140120Smckusick sizeof (struct sockaddr), MT_SONAME)) 16238414Smckusick return (error); 16338414Smckusick args.fh = &nfh; 16441904Smckusick error = mountnfs(&args, mp, nam, pth, hst); 16538414Smckusick return (error); 16638414Smckusick } 16738414Smckusick 16838414Smckusick /* 16938414Smckusick * Common code for mount and mountroot 17038414Smckusick */ 17141904Smckusick mountnfs(argp, mp, nam, pth, hst) 17238414Smckusick register struct nfs_args *argp; 17338414Smckusick register struct mount *mp; 17441904Smckusick struct mbuf *nam; 17538414Smckusick char *pth, *hst; 17638414Smckusick { 17738414Smckusick register struct nfsmount *nmp; 17840010Smckusick struct nfsnode *np; 17940120Smckusick int error; 18039757Smckusick fsid_t tfsid; 18138414Smckusick 18240120Smckusick MALLOC(nmp, struct nfsmount *, sizeof *nmp, M_NFSMNT, M_WAITOK); 18340120Smckusick bzero((caddr_t)nmp, sizeof *nmp); 18441398Smckusick mp->mnt_data = (qaddr_t)nmp; 18539757Smckusick /* 18639757Smckusick * Generate a unique nfs mount id. The problem is that a dev number 18739757Smckusick * is not unique across multiple systems. The techique is as follows: 18839757Smckusick * 1) Set to nblkdev,0 which will never be used otherwise 18939757Smckusick * 2) Generate a first guess as nblkdev,nfs_mntid where nfs_mntid is 19039757Smckusick * NOT 0 19139757Smckusick * 3) Loop searching the mount list for another one with same id 19239757Smckusick * If a match, increment val[0] and try again 19339757Smckusick * NB: I increment val[0] { a long } instead of nfs_mntid { a u_char } 19439757Smckusick * so that nfs is not limited to 255 mount points 19539757Smckusick * Incrementing the high order bits does no real harm, since it 19639757Smckusick * simply makes the major dev number tick up. The upper bound is 19739757Smckusick * set to major dev 127 to avoid any sign extention problems 19839757Smckusick */ 19941398Smckusick mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev, 0); 20041398Smckusick mp->mnt_stat.f_fsid.val[1] = MOUNT_NFS; 20139757Smckusick if (++nfs_mntid == 0) 20239757Smckusick ++nfs_mntid; 20339757Smckusick tfsid.val[0] = makedev(nblkdev, nfs_mntid); 20439757Smckusick tfsid.val[1] = MOUNT_NFS; 20539757Smckusick while (getvfs(&tfsid)) { 20639757Smckusick tfsid.val[0]++; 20739757Smckusick nfs_mntid++; 20839757Smckusick } 20939757Smckusick if (major(tfsid.val[0]) > 127) { 21039757Smckusick error = ENOENT; 21139757Smckusick goto bad; 21239757Smckusick } 21341398Smckusick mp->mnt_stat.f_fsid.val[0] = tfsid.val[0]; 21438414Smckusick nmp->nm_mountp = mp; 21538414Smckusick nmp->nm_flag = argp->flags; 21640120Smckusick nmp->nm_rto = NFS_TIMEO; 21740120Smckusick nmp->nm_rtt = -1; 21840120Smckusick nmp->nm_rttvar = nmp->nm_rto << 1; 21940120Smckusick nmp->nm_retry = NFS_RETRANS; 22040120Smckusick nmp->nm_wsize = NFS_WSIZE; 22140120Smckusick nmp->nm_rsize = NFS_RSIZE; 22240120Smckusick bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t)); 22341398Smckusick mp->mnt_stat.f_type = MOUNT_NFS; 22441398Smckusick bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); 22541398Smckusick bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN); 22641904Smckusick nmp->nm_nam = nam; 22740120Smckusick 22840120Smckusick if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { 22940120Smckusick nmp->nm_rto = argp->timeo; 23040120Smckusick /* NFS timeouts are specified in 1/10 sec. */ 23140120Smckusick nmp->nm_rto = (nmp->nm_rto * 10) / NFS_HZ; 23240120Smckusick if (nmp->nm_rto < NFS_MINTIMEO) 23340120Smckusick nmp->nm_rto = NFS_MINTIMEO; 23440120Smckusick else if (nmp->nm_rto > NFS_MAXTIMEO) 23540120Smckusick nmp->nm_rto = NFS_MAXTIMEO; 23640120Smckusick nmp->nm_rttvar = nmp->nm_rto << 1; 23740120Smckusick } 23840120Smckusick 23943355Smckusick if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) { 24040120Smckusick nmp->nm_retry = argp->retrans; 24140120Smckusick if (nmp->nm_retry > NFS_MAXREXMIT) 24240120Smckusick nmp->nm_retry = NFS_MAXREXMIT; 24340120Smckusick } 24440120Smckusick 24540120Smckusick if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { 24638414Smckusick nmp->nm_wsize = argp->wsize; 24740120Smckusick /* Round down to multiple of blocksize */ 24840120Smckusick nmp->nm_wsize &= ~0x1ff; 24940120Smckusick if (nmp->nm_wsize <= 0) 25040120Smckusick nmp->nm_wsize = 512; 25140120Smckusick else if (nmp->nm_wsize > NFS_MAXDATA) 25240120Smckusick nmp->nm_wsize = NFS_MAXDATA; 25340120Smckusick } 25443355Smckusick if (nmp->nm_wsize > MAXBSIZE) 25543355Smckusick nmp->nm_wsize = MAXBSIZE; 25640120Smckusick 25740120Smckusick if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { 25838414Smckusick nmp->nm_rsize = argp->rsize; 25940120Smckusick /* Round down to multiple of blocksize */ 26040120Smckusick nmp->nm_rsize &= ~0x1ff; 26140120Smckusick if (nmp->nm_rsize <= 0) 26240120Smckusick nmp->nm_rsize = 512; 26340120Smckusick else if (nmp->nm_rsize > NFS_MAXDATA) 26440120Smckusick nmp->nm_rsize = NFS_MAXDATA; 26540120Smckusick } 26643355Smckusick if (nmp->nm_rsize > MAXBSIZE) 26743355Smckusick nmp->nm_rsize = MAXBSIZE; 26840120Smckusick /* Set up the sockets and per-host congestion */ 26941904Smckusick nmp->nm_sotype = argp->sotype; 27041904Smckusick nmp->nm_soproto = argp->proto; 27141904Smckusick if (error = nfs_connect(nmp)) 27240120Smckusick goto bad; 27340120Smckusick 27441398Smckusick if (error = nfs_statfs(mp, &mp->mnt_stat)) 27540353Smckusick goto bad; 27638414Smckusick /* 27740010Smckusick * A reference count is needed on the nfsnode representing the 27840010Smckusick * remote root. If this object is not persistent, then backward 27940010Smckusick * traversals of the mount point (i.e. "..") will not work if 28040010Smckusick * the nfsnode gets flushed out of the cache. Ufs does not have 28140010Smckusick * this problem, because one can identify root inodes by their 28240010Smckusick * number == ROOTINO (2). 28340010Smckusick */ 28440010Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 28540010Smckusick goto bad; 28640010Smckusick /* 28740010Smckusick * Unlock it, but keep the reference count. 28840010Smckusick */ 28940010Smckusick nfs_unlock(NFSTOV(np)); 29041904Smckusick 29140353Smckusick return (0); 29238414Smckusick bad: 29340120Smckusick nfs_disconnect(nmp); 29440120Smckusick FREE(nmp, M_NFSMNT); 29541904Smckusick m_freem(nam); 29638414Smckusick return (error); 29738414Smckusick } 29838414Smckusick 29938414Smckusick /* 30038414Smckusick * unmount system call 30138414Smckusick */ 30241294Smckusick nfs_unmount(mp, mntflags) 30338414Smckusick struct mount *mp; 30441294Smckusick int mntflags; 30538414Smckusick { 30638414Smckusick register struct nfsmount *nmp; 30740010Smckusick struct nfsnode *np; 30840120Smckusick struct vnode *vp; 30941294Smckusick int flags = 0; 31038414Smckusick int error; 31138414Smckusick 31241294Smckusick if (mntflags & MNT_FORCE) 31338414Smckusick return (EINVAL); 31441294Smckusick if (mntflags & MNT_FORCE) 31541294Smckusick flags |= FORCECLOSE; 31641398Smckusick nmp = VFSTONFS(mp); 31738414Smckusick /* 31838884Smacklem * Clear out the buffer cache 31938884Smacklem */ 32039669Smckusick mntflushbuf(mp, 0); 32139669Smckusick if (mntinvalbuf(mp)) 32238884Smacklem return (EBUSY); 32338884Smacklem /* 32438414Smckusick * Goes something like this.. 32540120Smckusick * - Check for activity on the root vnode (other than ourselves). 32640120Smckusick * - Call vflush() to clear out vnodes for this file system, 32740120Smckusick * except for the root vnode. 32840120Smckusick * - Decrement reference on the vnode representing remote root. 32938414Smckusick * - Close the socket 33038414Smckusick * - Free up the data structures 33138414Smckusick */ 33240010Smckusick /* 33340010Smckusick * We need to decrement the ref. count on the nfsnode representing 33440010Smckusick * the remote root. See comment in mountnfs(). The VFS unmount() 33540010Smckusick * has done vput on this vnode, otherwise we would get deadlock! 33640010Smckusick */ 33740010Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 33840010Smckusick return(error); 33940120Smckusick vp = NFSTOV(np); 34040120Smckusick if (vp->v_usecount > 2) { 34140120Smckusick vput(vp); 34240120Smckusick return (EBUSY); 34340120Smckusick } 34440120Smckusick if (error = vflush(mp, vp, flags)) { 34540120Smckusick vput(vp); 34640120Smckusick return (error); 34740120Smckusick } 34840010Smckusick /* 34940010Smckusick * Get rid of two reference counts, and unlock it on the second. 35040010Smckusick */ 35140120Smckusick vrele(vp); 35240120Smckusick vput(vp); 35340120Smckusick nfs_disconnect(nmp); 35441904Smckusick m_freem(nmp->nm_nam); 35538414Smckusick free((caddr_t)nmp, M_NFSMNT); 35638414Smckusick return (0); 35738414Smckusick } 35838414Smckusick 35938414Smckusick /* 36038414Smckusick * Return root of a filesystem 36138414Smckusick */ 36238414Smckusick nfs_root(mp, vpp) 36338414Smckusick struct mount *mp; 36438414Smckusick struct vnode **vpp; 36538414Smckusick { 36638414Smckusick register struct vnode *vp; 36738414Smckusick struct nfsmount *nmp; 36838414Smckusick struct nfsnode *np; 36938414Smckusick int error; 37038414Smckusick 37141398Smckusick nmp = VFSTONFS(mp); 37238414Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 37338414Smckusick return (error); 37438414Smckusick vp = NFSTOV(np); 37538414Smckusick vp->v_type = VDIR; 37638414Smckusick vp->v_flag = VROOT; 37738414Smckusick *vpp = vp; 37838414Smckusick return (0); 37938414Smckusick } 38038414Smckusick 38138884Smacklem extern int syncprt; 38238884Smacklem 38338414Smckusick /* 38438884Smacklem * Flush out the buffer cache 38538414Smckusick */ 38639494Smckusick /* ARGSUSED */ 38738414Smckusick nfs_sync(mp, waitfor) 38838414Smckusick struct mount *mp; 38938414Smckusick int waitfor; 39038414Smckusick { 39138884Smacklem if (syncprt) 39238884Smacklem bufstats(); 39338884Smacklem /* 39438884Smacklem * Force stale buffer cache information to be flushed. 39538884Smacklem */ 39640035Smckusick mntflushbuf(mp, waitfor == MNT_WAIT ? B_SYNC : 0); 39738414Smckusick return (0); 39838414Smckusick } 39938414Smckusick 40038414Smckusick /* 40138414Smckusick * At this point, this should never happen 40238414Smckusick */ 40339494Smckusick /* ARGSUSED */ 40438414Smckusick nfs_fhtovp(mp, fhp, vpp) 40538414Smckusick struct mount *mp; 40638414Smckusick struct fid *fhp; 40738414Smckusick struct vnode **vpp; 40838414Smckusick { 40939494Smckusick 41038414Smckusick return (EINVAL); 41138414Smckusick } 41238414Smckusick 41338414Smckusick /* 41438414Smckusick * Vnode pointer to File handle, should never happen either 41538414Smckusick */ 41639494Smckusick /* ARGSUSED */ 41738414Smckusick nfs_vptofh(mp, fhp, vpp) 41838414Smckusick struct mount *mp; 41938414Smckusick struct fid *fhp; 42038414Smckusick struct vnode **vpp; 42138414Smckusick { 42239494Smckusick 42338414Smckusick return (EINVAL); 42438414Smckusick } 42538884Smacklem 42638884Smacklem /* 42738884Smacklem * Vfs start routine, a no-op. 42838884Smacklem */ 42939494Smckusick /* ARGSUSED */ 43038884Smacklem nfs_start(mp, flags) 43138884Smacklem struct mount *mp; 43238884Smacklem int flags; 43338884Smacklem { 43439494Smckusick 43538884Smacklem return (0); 43638884Smacklem } 43741294Smckusick 43841294Smckusick /* 43941294Smckusick * Do operations associated with quotas, not supported 44041294Smckusick */ 44141294Smckusick nfs_quotactl(mp, cmd, uid, arg) 44241294Smckusick struct mount *mp; 44341294Smckusick int cmd; 44441294Smckusick uid_t uid; 44541294Smckusick caddr_t arg; 44641294Smckusick { 44742245Smckusick #ifdef lint 44842245Smckusick mp = mp; cmd = cmd; uid = uid; arg = arg; 44942245Smckusick #endif /* lint */ 45041294Smckusick return (EOPNOTSUPP); 45141294Smckusick } 452