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 * 838414Smckusick * Redistribution and use in source and binary forms are permitted 938414Smckusick * provided that the above copyright notice and this paragraph are 1038414Smckusick * duplicated in all such forms and that any documentation, 1138414Smckusick * advertising materials, and other materials related to such 1238414Smckusick * distribution and use acknowledge that the software was developed 1338414Smckusick * by the University of California, Berkeley. The name of the 1438414Smckusick * University may not be used to endorse or promote products derived 1538414Smckusick * from this software without specific prior written permission. 1638414Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1738414Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1838414Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1938414Smckusick * 20*41904Smckusick * @(#)nfs_vfsops.c 7.21 (Berkeley) 05/14/90 2138414Smckusick */ 2238414Smckusick 2338414Smckusick #include "param.h" 2438414Smckusick #include "signal.h" 2538414Smckusick #include "user.h" 2638414Smckusick #include "proc.h" 2738414Smckusick #include "vnode.h" 2838414Smckusick #include "mount.h" 2938414Smckusick #include "errno.h" 3040120Smckusick #include "buf.h" 3138414Smckusick #include "mbuf.h" 3238414Smckusick #include "socket.h" 3340120Smckusick #include "systm.h" 3438414Smckusick #include "nfsv2.h" 3538414Smckusick #include "nfsnode.h" 3638414Smckusick #include "nfsmount.h" 3738414Smckusick #include "nfs.h" 38*41904Smckusick #include "xdr_subs.h" 39*41904Smckusick #include "nfsm_subs.h" 4038414Smckusick 4138414Smckusick /* 4238414Smckusick * nfs vfs operations. 4338414Smckusick */ 4438414Smckusick int nfs_mount(); 4538874Smckusick int nfs_start(); 4638414Smckusick int nfs_unmount(); 4738414Smckusick int nfs_root(); 4841294Smckusick int nfs_quotactl(); 4939443Smckusick int nfs_statfs(); 5038414Smckusick int nfs_sync(); 5138414Smckusick int nfs_fhtovp(); 5238414Smckusick int nfs_vptofh(); 5339443Smckusick int nfs_init(); 5438414Smckusick 5538414Smckusick struct vfsops nfs_vfsops = { 5638414Smckusick nfs_mount, 5738874Smckusick nfs_start, 5838414Smckusick nfs_unmount, 5938414Smckusick nfs_root, 6041294Smckusick nfs_quotactl, 6138414Smckusick nfs_statfs, 6238414Smckusick nfs_sync, 6338414Smckusick nfs_fhtovp, 6438414Smckusick nfs_vptofh, 6539443Smckusick nfs_init, 6638414Smckusick }; 6738414Smckusick 6839757Smckusick static u_char nfs_mntid; 69*41904Smckusick extern u_long nfs_procids[NFS_NPROCS]; 70*41904Smckusick extern u_long nfs_prog, nfs_vers; 71*41904Smckusick void nfs_disconnect(); 7238414Smckusick 73*41904Smckusick #define TRUE 1 74*41904Smckusick #define FALSE 0 75*41904Smckusick 7638414Smckusick /* 77*41904Smckusick * nfs statfs call 78*41904Smckusick */ 79*41904Smckusick nfs_statfs(mp, sbp) 80*41904Smckusick struct mount *mp; 81*41904Smckusick register struct statfs *sbp; 82*41904Smckusick { 83*41904Smckusick register struct vnode *vp; 84*41904Smckusick register struct nfsv2_statfs *sfp; 85*41904Smckusick register caddr_t cp; 86*41904Smckusick register long t1; 87*41904Smckusick caddr_t bpos, dpos, cp2; 88*41904Smckusick u_long xid; 89*41904Smckusick int error = 0; 90*41904Smckusick struct mbuf *mreq, *mrep, *md, *mb, *mb2; 91*41904Smckusick struct nfsmount *nmp; 92*41904Smckusick struct ucred *cred; 93*41904Smckusick struct nfsnode *np; 94*41904Smckusick 95*41904Smckusick nmp = VFSTONFS(mp); 96*41904Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 97*41904Smckusick return (error); 98*41904Smckusick vp = NFSTOV(np); 99*41904Smckusick nfsstats.rpccnt[NFSPROC_STATFS]++; 100*41904Smckusick cred = crget(); 101*41904Smckusick cred->cr_ngroups = 1; 102*41904Smckusick nfsm_reqhead(nfs_procids[NFSPROC_STATFS], cred, NFSX_FH); 103*41904Smckusick nfsm_fhtom(vp); 104*41904Smckusick nfsm_request(vp, NFSPROC_STATFS, u.u_procp); 105*41904Smckusick nfsm_disect(sfp, struct nfsv2_statfs *, NFSX_STATFS); 106*41904Smckusick sbp->f_type = MOUNT_NFS; 107*41904Smckusick sbp->f_flags = nmp->nm_flag; 108*41904Smckusick sbp->f_bsize = fxdr_unsigned(long, sfp->sf_tsize); 109*41904Smckusick sbp->f_fsize = fxdr_unsigned(long, sfp->sf_bsize); 110*41904Smckusick sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks); 111*41904Smckusick sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree); 112*41904Smckusick sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail); 113*41904Smckusick sbp->f_files = 0; 114*41904Smckusick sbp->f_ffree = 0; 115*41904Smckusick if (sbp != &mp->mnt_stat) { 116*41904Smckusick bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 117*41904Smckusick bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 118*41904Smckusick } 119*41904Smckusick nfsm_reqdone; 120*41904Smckusick nfs_nput(vp); 121*41904Smckusick crfree(cred); 122*41904Smckusick return (error); 123*41904Smckusick } 124*41904Smckusick 125*41904Smckusick /* 12638414Smckusick * Called by vfs_mountroot when nfs is going to be mounted as root 12738414Smckusick * Not Yet (By a LONG shot) 12838414Smckusick */ 12938414Smckusick nfs_mountroot() 13038414Smckusick { 13138414Smckusick return (ENODEV); 13238414Smckusick } 13338414Smckusick 13438414Smckusick /* 13538414Smckusick * VFS Operations. 13638414Smckusick * 13738414Smckusick * mount system call 13838414Smckusick * It seems a bit dumb to copyinstr() the host and path here and then 13938414Smckusick * bcopy() them in mountnfs(), but I wanted to detect errors before 14038414Smckusick * doing the sockargs() call because sockargs() allocates an mbuf and 14138414Smckusick * an error after that means that I have to release the mbuf. 14238414Smckusick */ 14339494Smckusick /* ARGSUSED */ 14438414Smckusick nfs_mount(mp, path, data, ndp) 14538414Smckusick struct mount *mp; 14638414Smckusick char *path; 14738414Smckusick caddr_t data; 14838414Smckusick struct nameidata *ndp; 14938414Smckusick { 15038414Smckusick int error; 15138414Smckusick struct nfs_args args; 152*41904Smckusick struct mbuf *nam; 15338414Smckusick char pth[MNAMELEN], hst[MNAMELEN]; 15438414Smckusick int len; 15538414Smckusick nfsv2fh_t nfh; 15638414Smckusick 15741398Smckusick if (mp->mnt_flag & MNT_UPDATE) 15839460Smckusick return (0); 15938414Smckusick if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args))) 16038414Smckusick return (error); 16138414Smckusick if (error=copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t))) 16238414Smckusick return (error); 16338414Smckusick if (error = copyinstr(path, pth, MNAMELEN-1, &len)) 16438414Smckusick return (error); 16538414Smckusick bzero(&pth[len], MNAMELEN-len); 16638414Smckusick if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len)) 16738414Smckusick return (error); 16838414Smckusick bzero(&hst[len], MNAMELEN-len); 16938414Smckusick /* sockargs() call must be after above copyin() calls */ 170*41904Smckusick if (error = sockargs(&nam, (caddr_t)args.addr, 17140120Smckusick sizeof (struct sockaddr), MT_SONAME)) 17238414Smckusick return (error); 17338414Smckusick args.fh = &nfh; 174*41904Smckusick error = mountnfs(&args, mp, nam, pth, hst); 17538414Smckusick return (error); 17638414Smckusick } 17738414Smckusick 17838414Smckusick /* 17938414Smckusick * Common code for mount and mountroot 18038414Smckusick */ 181*41904Smckusick mountnfs(argp, mp, nam, pth, hst) 18238414Smckusick register struct nfs_args *argp; 18338414Smckusick register struct mount *mp; 184*41904Smckusick struct mbuf *nam; 18538414Smckusick char *pth, *hst; 18638414Smckusick { 18738414Smckusick register struct nfsmount *nmp; 18840010Smckusick struct nfsnode *np; 18940120Smckusick int error; 19039757Smckusick fsid_t tfsid; 19138414Smckusick 19240120Smckusick MALLOC(nmp, struct nfsmount *, sizeof *nmp, M_NFSMNT, M_WAITOK); 19340120Smckusick bzero((caddr_t)nmp, sizeof *nmp); 19441398Smckusick mp->mnt_data = (qaddr_t)nmp; 19539757Smckusick /* 19639757Smckusick * Generate a unique nfs mount id. The problem is that a dev number 19739757Smckusick * is not unique across multiple systems. The techique is as follows: 19839757Smckusick * 1) Set to nblkdev,0 which will never be used otherwise 19939757Smckusick * 2) Generate a first guess as nblkdev,nfs_mntid where nfs_mntid is 20039757Smckusick * NOT 0 20139757Smckusick * 3) Loop searching the mount list for another one with same id 20239757Smckusick * If a match, increment val[0] and try again 20339757Smckusick * NB: I increment val[0] { a long } instead of nfs_mntid { a u_char } 20439757Smckusick * so that nfs is not limited to 255 mount points 20539757Smckusick * Incrementing the high order bits does no real harm, since it 20639757Smckusick * simply makes the major dev number tick up. The upper bound is 20739757Smckusick * set to major dev 127 to avoid any sign extention problems 20839757Smckusick */ 20941398Smckusick mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev, 0); 21041398Smckusick mp->mnt_stat.f_fsid.val[1] = MOUNT_NFS; 21139757Smckusick if (++nfs_mntid == 0) 21239757Smckusick ++nfs_mntid; 21339757Smckusick tfsid.val[0] = makedev(nblkdev, nfs_mntid); 21439757Smckusick tfsid.val[1] = MOUNT_NFS; 21539757Smckusick while (getvfs(&tfsid)) { 21639757Smckusick tfsid.val[0]++; 21739757Smckusick nfs_mntid++; 21839757Smckusick } 21939757Smckusick if (major(tfsid.val[0]) > 127) { 22039757Smckusick error = ENOENT; 22139757Smckusick goto bad; 22239757Smckusick } 22341398Smckusick mp->mnt_stat.f_fsid.val[0] = tfsid.val[0]; 22438414Smckusick nmp->nm_mountp = mp; 22538414Smckusick nmp->nm_flag = argp->flags; 22640120Smckusick nmp->nm_rto = NFS_TIMEO; 22740120Smckusick nmp->nm_rtt = -1; 22840120Smckusick nmp->nm_rttvar = nmp->nm_rto << 1; 22940120Smckusick nmp->nm_retry = NFS_RETRANS; 23040120Smckusick nmp->nm_wsize = NFS_WSIZE; 23140120Smckusick nmp->nm_rsize = NFS_RSIZE; 23240120Smckusick bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t)); 23341398Smckusick mp->mnt_stat.f_type = MOUNT_NFS; 23441398Smckusick bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); 23541398Smckusick bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN); 236*41904Smckusick nmp->nm_nam = nam; 23740120Smckusick 23840120Smckusick if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { 23940120Smckusick nmp->nm_rto = argp->timeo; 24040120Smckusick /* NFS timeouts are specified in 1/10 sec. */ 24140120Smckusick nmp->nm_rto = (nmp->nm_rto * 10) / NFS_HZ; 24240120Smckusick if (nmp->nm_rto < NFS_MINTIMEO) 24340120Smckusick nmp->nm_rto = NFS_MINTIMEO; 24440120Smckusick else if (nmp->nm_rto > NFS_MAXTIMEO) 24540120Smckusick nmp->nm_rto = NFS_MAXTIMEO; 24640120Smckusick nmp->nm_rttvar = nmp->nm_rto << 1; 24740120Smckusick } 24840120Smckusick 24940120Smckusick if ((argp->flags & NFSMNT_RETRANS) && argp->retrans >= 0) { 25040120Smckusick nmp->nm_retry = argp->retrans; 25140120Smckusick if (nmp->nm_retry > NFS_MAXREXMIT) 25240120Smckusick nmp->nm_retry = NFS_MAXREXMIT; 25340120Smckusick } 25440120Smckusick 25540120Smckusick if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { 25638414Smckusick nmp->nm_wsize = argp->wsize; 25740120Smckusick /* Round down to multiple of blocksize */ 25840120Smckusick nmp->nm_wsize &= ~0x1ff; 25940120Smckusick if (nmp->nm_wsize <= 0) 26040120Smckusick nmp->nm_wsize = 512; 26140120Smckusick else if (nmp->nm_wsize > NFS_MAXDATA) 26240120Smckusick nmp->nm_wsize = NFS_MAXDATA; 26340120Smckusick } 26440120Smckusick 26540120Smckusick if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { 26638414Smckusick nmp->nm_rsize = argp->rsize; 26740120Smckusick /* Round down to multiple of blocksize */ 26840120Smckusick nmp->nm_rsize &= ~0x1ff; 26940120Smckusick if (nmp->nm_rsize <= 0) 27040120Smckusick nmp->nm_rsize = 512; 27140120Smckusick else if (nmp->nm_rsize > NFS_MAXDATA) 27240120Smckusick nmp->nm_rsize = NFS_MAXDATA; 27340120Smckusick } 27440120Smckusick /* Set up the sockets and per-host congestion */ 275*41904Smckusick nmp->nm_sotype = argp->sotype; 276*41904Smckusick nmp->nm_soproto = argp->proto; 277*41904Smckusick if (error = nfs_connect(nmp)) 27840120Smckusick goto bad; 27940120Smckusick 28041398Smckusick if (error = nfs_statfs(mp, &mp->mnt_stat)) 28140353Smckusick goto bad; 28238414Smckusick /* 28340010Smckusick * A reference count is needed on the nfsnode representing the 28440010Smckusick * remote root. If this object is not persistent, then backward 28540010Smckusick * traversals of the mount point (i.e. "..") will not work if 28640010Smckusick * the nfsnode gets flushed out of the cache. Ufs does not have 28740010Smckusick * this problem, because one can identify root inodes by their 28840010Smckusick * number == ROOTINO (2). 28940010Smckusick */ 29040010Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 29140010Smckusick goto bad; 29240010Smckusick /* 29340010Smckusick * Unlock it, but keep the reference count. 29440010Smckusick */ 29540010Smckusick nfs_unlock(NFSTOV(np)); 296*41904Smckusick 29740353Smckusick return (0); 29838414Smckusick bad: 29940120Smckusick nfs_disconnect(nmp); 30040120Smckusick FREE(nmp, M_NFSMNT); 301*41904Smckusick m_freem(nam); 30238414Smckusick return (error); 30338414Smckusick } 30438414Smckusick 30538414Smckusick /* 30638414Smckusick * unmount system call 30738414Smckusick */ 30841294Smckusick nfs_unmount(mp, mntflags) 30938414Smckusick struct mount *mp; 31041294Smckusick int mntflags; 31138414Smckusick { 31238414Smckusick register struct nfsmount *nmp; 31338414Smckusick register struct nfsreq *rep; 31438414Smckusick struct nfsreq *rep2; 31540010Smckusick struct nfsnode *np; 31640120Smckusick struct vnode *vp; 31741294Smckusick int flags = 0; 31838414Smckusick int error; 31938414Smckusick int s; 32038414Smckusick 32141294Smckusick if (mntflags & MNT_FORCE) 32238414Smckusick return (EINVAL); 32341294Smckusick if (mntflags & MNT_FORCE) 32441294Smckusick flags |= FORCECLOSE; 32541398Smckusick nmp = VFSTONFS(mp); 32638414Smckusick /* 32738884Smacklem * Clear out the buffer cache 32838884Smacklem */ 32939669Smckusick mntflushbuf(mp, 0); 33039669Smckusick if (mntinvalbuf(mp)) 33138884Smacklem return (EBUSY); 33238884Smacklem /* 33338414Smckusick * Goes something like this.. 33440120Smckusick * - Check for activity on the root vnode (other than ourselves). 33540120Smckusick * - Call vflush() to clear out vnodes for this file system, 33640120Smckusick * except for the root vnode. 33740120Smckusick * - Decrement reference on the vnode representing remote root. 33838414Smckusick * - Close the socket 33938414Smckusick * - Free up the data structures 34038414Smckusick */ 34140010Smckusick /* 34240010Smckusick * We need to decrement the ref. count on the nfsnode representing 34340010Smckusick * the remote root. See comment in mountnfs(). The VFS unmount() 34440010Smckusick * has done vput on this vnode, otherwise we would get deadlock! 34540010Smckusick */ 34640010Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 34740010Smckusick return(error); 34840120Smckusick vp = NFSTOV(np); 34940120Smckusick if (vp->v_usecount > 2) { 35040120Smckusick vput(vp); 35140120Smckusick return (EBUSY); 35240120Smckusick } 35340120Smckusick if (error = vflush(mp, vp, flags)) { 35440120Smckusick vput(vp); 35540120Smckusick return (error); 35640120Smckusick } 35740010Smckusick /* 35840010Smckusick * Get rid of two reference counts, and unlock it on the second. 35940010Smckusick */ 36040120Smckusick vrele(vp); 36140120Smckusick vput(vp); 36240120Smckusick nfs_disconnect(nmp); 363*41904Smckusick m_freem(nmp->nm_nam); 36438414Smckusick free((caddr_t)nmp, M_NFSMNT); 36538414Smckusick return (0); 36638414Smckusick } 36738414Smckusick 36838414Smckusick /* 36938414Smckusick * Return root of a filesystem 37038414Smckusick */ 37138414Smckusick nfs_root(mp, vpp) 37238414Smckusick struct mount *mp; 37338414Smckusick struct vnode **vpp; 37438414Smckusick { 37538414Smckusick register struct vnode *vp; 37638414Smckusick struct nfsmount *nmp; 37738414Smckusick struct nfsnode *np; 37838414Smckusick int error; 37938414Smckusick 38041398Smckusick nmp = VFSTONFS(mp); 38138414Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 38238414Smckusick return (error); 38338414Smckusick vp = NFSTOV(np); 38438414Smckusick vp->v_type = VDIR; 38538414Smckusick vp->v_flag = VROOT; 38638414Smckusick *vpp = vp; 38738414Smckusick return (0); 38838414Smckusick } 38938414Smckusick 39038884Smacklem extern int syncprt; 39138884Smacklem 39238414Smckusick /* 39338884Smacklem * Flush out the buffer cache 39438414Smckusick */ 39539494Smckusick /* ARGSUSED */ 39638414Smckusick nfs_sync(mp, waitfor) 39738414Smckusick struct mount *mp; 39838414Smckusick int waitfor; 39938414Smckusick { 40038884Smacklem if (syncprt) 40138884Smacklem bufstats(); 40238884Smacklem /* 40338884Smacklem * Force stale buffer cache information to be flushed. 40438884Smacklem */ 40540035Smckusick mntflushbuf(mp, waitfor == MNT_WAIT ? B_SYNC : 0); 40638414Smckusick return (0); 40738414Smckusick } 40838414Smckusick 40938414Smckusick /* 41038414Smckusick * At this point, this should never happen 41138414Smckusick */ 41239494Smckusick /* ARGSUSED */ 41338414Smckusick nfs_fhtovp(mp, fhp, vpp) 41438414Smckusick struct mount *mp; 41538414Smckusick struct fid *fhp; 41638414Smckusick struct vnode **vpp; 41738414Smckusick { 41839494Smckusick 41938414Smckusick return (EINVAL); 42038414Smckusick } 42138414Smckusick 42238414Smckusick /* 42338414Smckusick * Vnode pointer to File handle, should never happen either 42438414Smckusick */ 42539494Smckusick /* ARGSUSED */ 42638414Smckusick nfs_vptofh(mp, fhp, vpp) 42738414Smckusick struct mount *mp; 42838414Smckusick struct fid *fhp; 42938414Smckusick struct vnode **vpp; 43038414Smckusick { 43139494Smckusick 43238414Smckusick return (EINVAL); 43338414Smckusick } 43438884Smacklem 43538884Smacklem /* 43638884Smacklem * Vfs start routine, a no-op. 43738884Smacklem */ 43839494Smckusick /* ARGSUSED */ 43938884Smacklem nfs_start(mp, flags) 44038884Smacklem struct mount *mp; 44138884Smacklem int flags; 44238884Smacklem { 44339494Smckusick 44438884Smacklem return (0); 44538884Smacklem } 44641294Smckusick 44741294Smckusick /* 44841294Smckusick * Do operations associated with quotas, not supported 44941294Smckusick */ 45041294Smckusick nfs_quotactl(mp, cmd, uid, arg) 45141294Smckusick struct mount *mp; 45241294Smckusick int cmd; 45341294Smckusick uid_t uid; 45441294Smckusick caddr_t arg; 45541294Smckusick { 45641294Smckusick return (EOPNOTSUPP); 45741294Smckusick } 458