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*40120Smckusick * @(#)nfs_vfsops.c 7.15 (Berkeley) 02/16/90 2138414Smckusick */ 2238414Smckusick 2338414Smckusick #include "param.h" 2438414Smckusick #include "signal.h" 2538414Smckusick #include "user.h" 2638414Smckusick #include "proc.h" 2738414Smckusick #include "uio.h" 2838414Smckusick #include "ucred.h" 29*40120Smckusick #include "ufs/dir.h" 3038414Smckusick #include "namei.h" 3138414Smckusick #include "vnode.h" 3238414Smckusick #include "mount.h" 3338414Smckusick #include "errno.h" 3438414Smckusick #include "malloc.h" 35*40120Smckusick #include "buf.h" 3638414Smckusick #include "mbuf.h" 3738414Smckusick #undef m_data 3838414Smckusick #include "socket.h" 39*40120Smckusick #include "systm.h" 4038414Smckusick #include "nfsv2.h" 4138414Smckusick #include "nfsnode.h" 4238414Smckusick #include "nfsmount.h" 4338414Smckusick #include "nfs.h" 4438414Smckusick 4538414Smckusick /* 4638414Smckusick * nfs vfs operations. 4738414Smckusick */ 4838414Smckusick int nfs_mount(); 4938874Smckusick int nfs_start(); 5038414Smckusick int nfs_unmount(); 5138414Smckusick int nfs_root(); 5239443Smckusick int nfs_statfs(); 5338414Smckusick int nfs_sync(); 5438414Smckusick int nfs_fhtovp(); 5538414Smckusick int nfs_vptofh(); 5639443Smckusick int nfs_init(); 5738414Smckusick 5838414Smckusick struct vfsops nfs_vfsops = { 5938414Smckusick nfs_mount, 6038874Smckusick nfs_start, 6138414Smckusick nfs_unmount, 6238414Smckusick nfs_root, 6338414Smckusick nfs_statfs, 6438414Smckusick nfs_sync, 6538414Smckusick nfs_fhtovp, 6638414Smckusick nfs_vptofh, 6739443Smckusick nfs_init, 6838414Smckusick }; 6938414Smckusick 7039757Smckusick static u_char nfs_mntid; 7138414Smckusick 7238414Smckusick /* 7338414Smckusick * Called by vfs_mountroot when nfs is going to be mounted as root 7438414Smckusick * Not Yet (By a LONG shot) 7538414Smckusick */ 7638414Smckusick nfs_mountroot() 7738414Smckusick { 7838414Smckusick return (ENODEV); 7938414Smckusick } 8038414Smckusick 8138414Smckusick /* 8238414Smckusick * VFS Operations. 8338414Smckusick * 8438414Smckusick * mount system call 8538414Smckusick * It seems a bit dumb to copyinstr() the host and path here and then 8638414Smckusick * bcopy() them in mountnfs(), but I wanted to detect errors before 8738414Smckusick * doing the sockargs() call because sockargs() allocates an mbuf and 8838414Smckusick * an error after that means that I have to release the mbuf. 8938414Smckusick */ 9039494Smckusick /* ARGSUSED */ 9138414Smckusick nfs_mount(mp, path, data, ndp) 9238414Smckusick struct mount *mp; 9338414Smckusick char *path; 9438414Smckusick caddr_t data; 9538414Smckusick struct nameidata *ndp; 9638414Smckusick { 9738414Smckusick int error; 9838414Smckusick struct nfs_args args; 9938414Smckusick struct mbuf *saddr; 10038414Smckusick char pth[MNAMELEN], hst[MNAMELEN]; 10138414Smckusick int len; 10238414Smckusick nfsv2fh_t nfh; 10338414Smckusick 10439460Smckusick if (mp->m_flag & M_UPDATE) 10539460Smckusick return (0); 10638414Smckusick if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args))) 10738414Smckusick return (error); 10838414Smckusick if (error=copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t))) 10938414Smckusick return (error); 11038414Smckusick if (error = copyinstr(path, pth, MNAMELEN-1, &len)) 11138414Smckusick return (error); 11238414Smckusick bzero(&pth[len], MNAMELEN-len); 11338414Smckusick if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len)) 11438414Smckusick return (error); 11538414Smckusick bzero(&hst[len], MNAMELEN-len); 11638414Smckusick /* sockargs() call must be after above copyin() calls */ 11738414Smckusick if (error = sockargs(&saddr, (caddr_t)args.addr, 118*40120Smckusick sizeof (struct sockaddr), MT_SONAME)) 11938414Smckusick return (error); 12038414Smckusick args.fh = &nfh; 12138414Smckusick error = mountnfs(&args, mp, saddr, pth, hst); 12238414Smckusick return (error); 12338414Smckusick } 12438414Smckusick 12538414Smckusick /* 12638414Smckusick * Common code for mount and mountroot 12738414Smckusick */ 12838414Smckusick mountnfs(argp, mp, saddr, pth, hst) 12938414Smckusick register struct nfs_args *argp; 13038414Smckusick register struct mount *mp; 13138414Smckusick register struct mbuf *saddr; 13238414Smckusick char *pth, *hst; 13338414Smckusick { 13438414Smckusick register struct nfsmount *nmp; 13540010Smckusick struct nfsnode *np; 136*40120Smckusick int error; 13739757Smckusick fsid_t tfsid; 13838414Smckusick 139*40120Smckusick MALLOC(nmp, struct nfsmount *, sizeof *nmp, M_NFSMNT, M_WAITOK); 140*40120Smckusick bzero((caddr_t)nmp, sizeof *nmp); 14138414Smckusick mp->m_data = (qaddr_t)nmp; 14239757Smckusick /* 14339757Smckusick * Generate a unique nfs mount id. The problem is that a dev number 14439757Smckusick * is not unique across multiple systems. The techique is as follows: 14539757Smckusick * 1) Set to nblkdev,0 which will never be used otherwise 14639757Smckusick * 2) Generate a first guess as nblkdev,nfs_mntid where nfs_mntid is 14739757Smckusick * NOT 0 14839757Smckusick * 3) Loop searching the mount list for another one with same id 14939757Smckusick * If a match, increment val[0] and try again 15039757Smckusick * NB: I increment val[0] { a long } instead of nfs_mntid { a u_char } 15139757Smckusick * so that nfs is not limited to 255 mount points 15239757Smckusick * Incrementing the high order bits does no real harm, since it 15339757Smckusick * simply makes the major dev number tick up. The upper bound is 15439757Smckusick * set to major dev 127 to avoid any sign extention problems 15539757Smckusick */ 15639757Smckusick mp->m_fsid.val[0] = makedev(nblkdev, 0); 15738414Smckusick mp->m_fsid.val[1] = MOUNT_NFS; 15839757Smckusick if (++nfs_mntid == 0) 15939757Smckusick ++nfs_mntid; 16039757Smckusick tfsid.val[0] = makedev(nblkdev, nfs_mntid); 16139757Smckusick tfsid.val[1] = MOUNT_NFS; 16239757Smckusick while (getvfs(&tfsid)) { 16339757Smckusick tfsid.val[0]++; 16439757Smckusick nfs_mntid++; 16539757Smckusick } 16639757Smckusick if (major(tfsid.val[0]) > 127) { 16739757Smckusick error = ENOENT; 16839757Smckusick goto bad; 16939757Smckusick } 17039757Smckusick mp->m_fsid.val[0] = tfsid.val[0]; 17138414Smckusick nmp->nm_mountp = mp; 17238414Smckusick nmp->nm_flag = argp->flags; 173*40120Smckusick nmp->nm_rto = NFS_TIMEO; 174*40120Smckusick nmp->nm_rtt = -1; 175*40120Smckusick nmp->nm_rttvar = nmp->nm_rto << 1; 176*40120Smckusick nmp->nm_retry = NFS_RETRANS; 177*40120Smckusick nmp->nm_wsize = NFS_WSIZE; 178*40120Smckusick nmp->nm_rsize = NFS_RSIZE; 179*40120Smckusick bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t)); 180*40120Smckusick bcopy(hst, nmp->nm_host, sizeof nmp->nm_host); 181*40120Smckusick bcopy(pth, nmp->nm_path, sizeof nmp->nm_path); 182*40120Smckusick 183*40120Smckusick if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { 184*40120Smckusick nmp->nm_rto = argp->timeo; 185*40120Smckusick /* NFS timeouts are specified in 1/10 sec. */ 186*40120Smckusick nmp->nm_rto = (nmp->nm_rto * 10) / NFS_HZ; 187*40120Smckusick if (nmp->nm_rto < NFS_MINTIMEO) 188*40120Smckusick nmp->nm_rto = NFS_MINTIMEO; 189*40120Smckusick else if (nmp->nm_rto > NFS_MAXTIMEO) 190*40120Smckusick nmp->nm_rto = NFS_MAXTIMEO; 191*40120Smckusick nmp->nm_rttvar = nmp->nm_rto << 1; 192*40120Smckusick } 193*40120Smckusick 194*40120Smckusick if ((argp->flags & NFSMNT_RETRANS) && argp->retrans >= 0) { 195*40120Smckusick nmp->nm_retry = argp->retrans; 196*40120Smckusick if (nmp->nm_retry > NFS_MAXREXMIT) 197*40120Smckusick nmp->nm_retry = NFS_MAXREXMIT; 198*40120Smckusick } 199*40120Smckusick 200*40120Smckusick if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { 20138414Smckusick nmp->nm_wsize = argp->wsize; 202*40120Smckusick /* Round down to multiple of blocksize */ 203*40120Smckusick nmp->nm_wsize &= ~0x1ff; 204*40120Smckusick if (nmp->nm_wsize <= 0) 205*40120Smckusick nmp->nm_wsize = 512; 206*40120Smckusick else if (nmp->nm_wsize > NFS_MAXDATA) 207*40120Smckusick nmp->nm_wsize = NFS_MAXDATA; 208*40120Smckusick } 209*40120Smckusick 210*40120Smckusick if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { 21138414Smckusick nmp->nm_rsize = argp->rsize; 212*40120Smckusick /* Round down to multiple of blocksize */ 213*40120Smckusick nmp->nm_rsize &= ~0x1ff; 214*40120Smckusick if (nmp->nm_rsize <= 0) 215*40120Smckusick nmp->nm_rsize = 512; 216*40120Smckusick else if (nmp->nm_rsize > NFS_MAXDATA) 217*40120Smckusick nmp->nm_rsize = NFS_MAXDATA; 218*40120Smckusick } 219*40120Smckusick /* Set up the sockets and per-host congestion */ 220*40120Smckusick if (error = nfs_connect(nmp, saddr)) 221*40120Smckusick goto bad; 222*40120Smckusick 22338414Smckusick /* 22438425Smckusick * Set to CLBYTES so that vinifod() doesn't get confused. 22538425Smckusick * Actually any exact multiple of CLBYTES will do 22638425Smckusick */ 22738425Smckusick mp->m_bsize = mp->m_fsize = CLBYTES; 22840010Smckusick /* 22940010Smckusick * A reference count is needed on the nfsnode representing the 23040010Smckusick * remote root. If this object is not persistent, then backward 23140010Smckusick * traversals of the mount point (i.e. "..") will not work if 23240010Smckusick * the nfsnode gets flushed out of the cache. Ufs does not have 23340010Smckusick * this problem, because one can identify root inodes by their 23440010Smckusick * number == ROOTINO (2). 23540010Smckusick */ 23640010Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 23740010Smckusick goto bad; 23840010Smckusick /* 23940010Smckusick * Unlock it, but keep the reference count. 24040010Smckusick */ 24140010Smckusick nfs_unlock(NFSTOV(np)); 242*40120Smckusick 24338414Smckusick return (0); 24438414Smckusick bad: 245*40120Smckusick nfs_disconnect(nmp); 246*40120Smckusick FREE(nmp, M_NFSMNT); 24738414Smckusick m_freem(saddr); 24838414Smckusick return (error); 24938414Smckusick } 25038414Smckusick 25138414Smckusick /* 25238414Smckusick * unmount system call 25338414Smckusick */ 25438414Smckusick nfs_unmount(mp, flags) 25538414Smckusick struct mount *mp; 25638414Smckusick int flags; 25738414Smckusick { 25838414Smckusick register struct nfsmount *nmp; 25938414Smckusick register struct nfsreq *rep; 26038414Smckusick struct nfsreq *rep2; 26140010Smckusick struct nfsnode *np; 262*40120Smckusick struct vnode *vp; 26338414Smckusick int error; 26438414Smckusick int s; 26538414Smckusick 26638414Smckusick if (flags & MNT_FORCE) 26738414Smckusick return (EINVAL); 26838414Smckusick nmp = vfs_to_nfs(mp); 26938414Smckusick /* 27038884Smacklem * Clear out the buffer cache 27138884Smacklem */ 27239669Smckusick mntflushbuf(mp, 0); 27339669Smckusick if (mntinvalbuf(mp)) 27438884Smacklem return (EBUSY); 27538884Smacklem /* 27638414Smckusick * Goes something like this.. 277*40120Smckusick * - Check for activity on the root vnode (other than ourselves). 278*40120Smckusick * - Call vflush() to clear out vnodes for this file system, 279*40120Smckusick * except for the root vnode. 280*40120Smckusick * - Decrement reference on the vnode representing remote root. 28138414Smckusick * - Close the socket 28238414Smckusick * - Free up the data structures 28338414Smckusick */ 28440010Smckusick /* 28540010Smckusick * We need to decrement the ref. count on the nfsnode representing 28640010Smckusick * the remote root. See comment in mountnfs(). The VFS unmount() 28740010Smckusick * has done vput on this vnode, otherwise we would get deadlock! 28840010Smckusick */ 28940010Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 29040010Smckusick return(error); 291*40120Smckusick vp = NFSTOV(np); 292*40120Smckusick if (vp->v_usecount > 2) { 293*40120Smckusick vput(vp); 294*40120Smckusick return (EBUSY); 295*40120Smckusick } 296*40120Smckusick if (error = vflush(mp, vp, flags)) { 297*40120Smckusick vput(vp); 298*40120Smckusick return (error); 299*40120Smckusick } 30040010Smckusick /* 30140010Smckusick * Get rid of two reference counts, and unlock it on the second. 30240010Smckusick */ 303*40120Smckusick vrele(vp); 304*40120Smckusick vput(vp); 305*40120Smckusick nfs_disconnect(nmp); 30638414Smckusick free((caddr_t)nmp, M_NFSMNT); 30738414Smckusick return (0); 30838414Smckusick } 30938414Smckusick 31038414Smckusick /* 31138414Smckusick * Return root of a filesystem 31238414Smckusick */ 31338414Smckusick nfs_root(mp, vpp) 31438414Smckusick struct mount *mp; 31538414Smckusick struct vnode **vpp; 31638414Smckusick { 31738414Smckusick register struct vnode *vp; 31838414Smckusick struct nfsmount *nmp; 31938414Smckusick struct nfsnode *np; 32038414Smckusick int error; 32138414Smckusick 32238414Smckusick nmp = vfs_to_nfs(mp); 32338414Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 32438414Smckusick return (error); 32538414Smckusick vp = NFSTOV(np); 32638414Smckusick vp->v_type = VDIR; 32738414Smckusick vp->v_flag = VROOT; 32838414Smckusick *vpp = vp; 32938414Smckusick return (0); 33038414Smckusick } 33138414Smckusick 33238884Smacklem extern int syncprt; 33338884Smacklem 33438414Smckusick /* 33538884Smacklem * Flush out the buffer cache 33638414Smckusick */ 33739494Smckusick /* ARGSUSED */ 33838414Smckusick nfs_sync(mp, waitfor) 33938414Smckusick struct mount *mp; 34038414Smckusick int waitfor; 34138414Smckusick { 34238884Smacklem if (syncprt) 34338884Smacklem bufstats(); 34438884Smacklem /* 34538884Smacklem * Force stale buffer cache information to be flushed. 34638884Smacklem */ 34740035Smckusick mntflushbuf(mp, waitfor == MNT_WAIT ? B_SYNC : 0); 34838414Smckusick return (0); 34938414Smckusick } 35038414Smckusick 35138414Smckusick /* 35238414Smckusick * At this point, this should never happen 35338414Smckusick */ 35439494Smckusick /* ARGSUSED */ 35538414Smckusick nfs_fhtovp(mp, fhp, vpp) 35638414Smckusick struct mount *mp; 35738414Smckusick struct fid *fhp; 35838414Smckusick struct vnode **vpp; 35938414Smckusick { 36039494Smckusick 36138414Smckusick return (EINVAL); 36238414Smckusick } 36338414Smckusick 36438414Smckusick /* 36538414Smckusick * Vnode pointer to File handle, should never happen either 36638414Smckusick */ 36739494Smckusick /* ARGSUSED */ 36838414Smckusick nfs_vptofh(mp, fhp, vpp) 36938414Smckusick struct mount *mp; 37038414Smckusick struct fid *fhp; 37138414Smckusick struct vnode **vpp; 37238414Smckusick { 37339494Smckusick 37438414Smckusick return (EINVAL); 37538414Smckusick } 37638884Smacklem 37738884Smacklem /* 37838884Smacklem * Vfs start routine, a no-op. 37938884Smacklem */ 38039494Smckusick /* ARGSUSED */ 38138884Smacklem nfs_start(mp, flags) 38238884Smacklem struct mount *mp; 38338884Smacklem int flags; 38438884Smacklem { 38539494Smckusick 38638884Smacklem return (0); 38738884Smacklem } 388