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*41398Smckusick * @(#)nfs_vfsops.c 7.20 (Berkeley) 05/04/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" 3838414Smckusick 3938414Smckusick /* 4038414Smckusick * nfs vfs operations. 4138414Smckusick */ 4238414Smckusick int nfs_mount(); 4338874Smckusick int nfs_start(); 4438414Smckusick int nfs_unmount(); 4538414Smckusick int nfs_root(); 4641294Smckusick int nfs_quotactl(); 4739443Smckusick int nfs_statfs(); 4838414Smckusick int nfs_sync(); 4938414Smckusick int nfs_fhtovp(); 5038414Smckusick int nfs_vptofh(); 5139443Smckusick int nfs_init(); 5238414Smckusick 5338414Smckusick struct vfsops nfs_vfsops = { 5438414Smckusick nfs_mount, 5538874Smckusick nfs_start, 5638414Smckusick nfs_unmount, 5738414Smckusick nfs_root, 5841294Smckusick nfs_quotactl, 5938414Smckusick nfs_statfs, 6038414Smckusick nfs_sync, 6138414Smckusick nfs_fhtovp, 6238414Smckusick nfs_vptofh, 6339443Smckusick nfs_init, 6438414Smckusick }; 6538414Smckusick 6639757Smckusick static u_char nfs_mntid; 6738414Smckusick 6838414Smckusick /* 6938414Smckusick * Called by vfs_mountroot when nfs is going to be mounted as root 7038414Smckusick * Not Yet (By a LONG shot) 7138414Smckusick */ 7238414Smckusick nfs_mountroot() 7338414Smckusick { 7438414Smckusick return (ENODEV); 7538414Smckusick } 7638414Smckusick 7738414Smckusick /* 7838414Smckusick * VFS Operations. 7938414Smckusick * 8038414Smckusick * mount system call 8138414Smckusick * It seems a bit dumb to copyinstr() the host and path here and then 8238414Smckusick * bcopy() them in mountnfs(), but I wanted to detect errors before 8338414Smckusick * doing the sockargs() call because sockargs() allocates an mbuf and 8438414Smckusick * an error after that means that I have to release the mbuf. 8538414Smckusick */ 8639494Smckusick /* ARGSUSED */ 8738414Smckusick nfs_mount(mp, path, data, ndp) 8838414Smckusick struct mount *mp; 8938414Smckusick char *path; 9038414Smckusick caddr_t data; 9138414Smckusick struct nameidata *ndp; 9238414Smckusick { 9338414Smckusick int error; 9438414Smckusick struct nfs_args args; 9538414Smckusick struct mbuf *saddr; 9638414Smckusick char pth[MNAMELEN], hst[MNAMELEN]; 9738414Smckusick int len; 9838414Smckusick nfsv2fh_t nfh; 9938414Smckusick 100*41398Smckusick if (mp->mnt_flag & MNT_UPDATE) 10139460Smckusick return (0); 10238414Smckusick if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args))) 10338414Smckusick return (error); 10438414Smckusick if (error=copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t))) 10538414Smckusick return (error); 10638414Smckusick if (error = copyinstr(path, pth, MNAMELEN-1, &len)) 10738414Smckusick return (error); 10838414Smckusick bzero(&pth[len], MNAMELEN-len); 10938414Smckusick if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len)) 11038414Smckusick return (error); 11138414Smckusick bzero(&hst[len], MNAMELEN-len); 11238414Smckusick /* sockargs() call must be after above copyin() calls */ 11338414Smckusick if (error = sockargs(&saddr, (caddr_t)args.addr, 11440120Smckusick sizeof (struct sockaddr), MT_SONAME)) 11538414Smckusick return (error); 11638414Smckusick args.fh = &nfh; 11738414Smckusick error = mountnfs(&args, mp, saddr, pth, hst); 11838414Smckusick return (error); 11938414Smckusick } 12038414Smckusick 12138414Smckusick /* 12238414Smckusick * Common code for mount and mountroot 12338414Smckusick */ 12438414Smckusick mountnfs(argp, mp, saddr, pth, hst) 12538414Smckusick register struct nfs_args *argp; 12638414Smckusick register struct mount *mp; 12738414Smckusick register struct mbuf *saddr; 12838414Smckusick char *pth, *hst; 12938414Smckusick { 13038414Smckusick register struct nfsmount *nmp; 13140010Smckusick struct nfsnode *np; 13240120Smckusick int error; 13339757Smckusick fsid_t tfsid; 13438414Smckusick 13540120Smckusick MALLOC(nmp, struct nfsmount *, sizeof *nmp, M_NFSMNT, M_WAITOK); 13640120Smckusick bzero((caddr_t)nmp, sizeof *nmp); 137*41398Smckusick mp->mnt_data = (qaddr_t)nmp; 13839757Smckusick /* 13939757Smckusick * Generate a unique nfs mount id. The problem is that a dev number 14039757Smckusick * is not unique across multiple systems. The techique is as follows: 14139757Smckusick * 1) Set to nblkdev,0 which will never be used otherwise 14239757Smckusick * 2) Generate a first guess as nblkdev,nfs_mntid where nfs_mntid is 14339757Smckusick * NOT 0 14439757Smckusick * 3) Loop searching the mount list for another one with same id 14539757Smckusick * If a match, increment val[0] and try again 14639757Smckusick * NB: I increment val[0] { a long } instead of nfs_mntid { a u_char } 14739757Smckusick * so that nfs is not limited to 255 mount points 14839757Smckusick * Incrementing the high order bits does no real harm, since it 14939757Smckusick * simply makes the major dev number tick up. The upper bound is 15039757Smckusick * set to major dev 127 to avoid any sign extention problems 15139757Smckusick */ 152*41398Smckusick mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev, 0); 153*41398Smckusick mp->mnt_stat.f_fsid.val[1] = MOUNT_NFS; 15439757Smckusick if (++nfs_mntid == 0) 15539757Smckusick ++nfs_mntid; 15639757Smckusick tfsid.val[0] = makedev(nblkdev, nfs_mntid); 15739757Smckusick tfsid.val[1] = MOUNT_NFS; 15839757Smckusick while (getvfs(&tfsid)) { 15939757Smckusick tfsid.val[0]++; 16039757Smckusick nfs_mntid++; 16139757Smckusick } 16239757Smckusick if (major(tfsid.val[0]) > 127) { 16339757Smckusick error = ENOENT; 16440553Smckusick m_freem(saddr); 16539757Smckusick goto bad; 16639757Smckusick } 167*41398Smckusick mp->mnt_stat.f_fsid.val[0] = tfsid.val[0]; 16838414Smckusick nmp->nm_mountp = mp; 16938414Smckusick nmp->nm_flag = argp->flags; 17040120Smckusick nmp->nm_rto = NFS_TIMEO; 17140120Smckusick nmp->nm_rtt = -1; 17240120Smckusick nmp->nm_rttvar = nmp->nm_rto << 1; 17340120Smckusick nmp->nm_retry = NFS_RETRANS; 17440120Smckusick nmp->nm_wsize = NFS_WSIZE; 17540120Smckusick nmp->nm_rsize = NFS_RSIZE; 17640120Smckusick bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t)); 177*41398Smckusick mp->mnt_stat.f_type = MOUNT_NFS; 178*41398Smckusick bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); 179*41398Smckusick bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN); 18040120Smckusick 18140120Smckusick if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { 18240120Smckusick nmp->nm_rto = argp->timeo; 18340120Smckusick /* NFS timeouts are specified in 1/10 sec. */ 18440120Smckusick nmp->nm_rto = (nmp->nm_rto * 10) / NFS_HZ; 18540120Smckusick if (nmp->nm_rto < NFS_MINTIMEO) 18640120Smckusick nmp->nm_rto = NFS_MINTIMEO; 18740120Smckusick else if (nmp->nm_rto > NFS_MAXTIMEO) 18840120Smckusick nmp->nm_rto = NFS_MAXTIMEO; 18940120Smckusick nmp->nm_rttvar = nmp->nm_rto << 1; 19040120Smckusick } 19140120Smckusick 19240120Smckusick if ((argp->flags & NFSMNT_RETRANS) && argp->retrans >= 0) { 19340120Smckusick nmp->nm_retry = argp->retrans; 19440120Smckusick if (nmp->nm_retry > NFS_MAXREXMIT) 19540120Smckusick nmp->nm_retry = NFS_MAXREXMIT; 19640120Smckusick } 19740120Smckusick 19840120Smckusick if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { 19938414Smckusick nmp->nm_wsize = argp->wsize; 20040120Smckusick /* Round down to multiple of blocksize */ 20140120Smckusick nmp->nm_wsize &= ~0x1ff; 20240120Smckusick if (nmp->nm_wsize <= 0) 20340120Smckusick nmp->nm_wsize = 512; 20440120Smckusick else if (nmp->nm_wsize > NFS_MAXDATA) 20540120Smckusick nmp->nm_wsize = NFS_MAXDATA; 20640120Smckusick } 20740120Smckusick 20840120Smckusick if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { 20938414Smckusick nmp->nm_rsize = argp->rsize; 21040120Smckusick /* Round down to multiple of blocksize */ 21140120Smckusick nmp->nm_rsize &= ~0x1ff; 21240120Smckusick if (nmp->nm_rsize <= 0) 21340120Smckusick nmp->nm_rsize = 512; 21440120Smckusick else if (nmp->nm_rsize > NFS_MAXDATA) 21540120Smckusick nmp->nm_rsize = NFS_MAXDATA; 21640120Smckusick } 21740120Smckusick /* Set up the sockets and per-host congestion */ 21840553Smckusick if (error = nfs_connect(nmp, saddr)) { 21940553Smckusick m_freem(saddr); 22040120Smckusick goto bad; 22140553Smckusick } 22240120Smckusick 223*41398Smckusick if (error = nfs_statfs(mp, &mp->mnt_stat)) 22440353Smckusick goto bad; 22538414Smckusick /* 22640010Smckusick * A reference count is needed on the nfsnode representing the 22740010Smckusick * remote root. If this object is not persistent, then backward 22840010Smckusick * traversals of the mount point (i.e. "..") will not work if 22940010Smckusick * the nfsnode gets flushed out of the cache. Ufs does not have 23040010Smckusick * this problem, because one can identify root inodes by their 23140010Smckusick * number == ROOTINO (2). 23240010Smckusick */ 23340010Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 23440010Smckusick goto bad; 23540010Smckusick /* 23640010Smckusick * Unlock it, but keep the reference count. 23740010Smckusick */ 23840010Smckusick nfs_unlock(NFSTOV(np)); 23940353Smckusick return (0); 24040120Smckusick 24138414Smckusick bad: 24240120Smckusick nfs_disconnect(nmp); 24340120Smckusick FREE(nmp, M_NFSMNT); 24438414Smckusick return (error); 24538414Smckusick } 24638414Smckusick 24738414Smckusick /* 24838414Smckusick * unmount system call 24938414Smckusick */ 25041294Smckusick nfs_unmount(mp, mntflags) 25138414Smckusick struct mount *mp; 25241294Smckusick int mntflags; 25338414Smckusick { 25438414Smckusick register struct nfsmount *nmp; 25538414Smckusick register struct nfsreq *rep; 25638414Smckusick struct nfsreq *rep2; 25740010Smckusick struct nfsnode *np; 25840120Smckusick struct vnode *vp; 25941294Smckusick int flags = 0; 26038414Smckusick int error; 26138414Smckusick int s; 26238414Smckusick 26341294Smckusick if (mntflags & MNT_FORCE) 26438414Smckusick return (EINVAL); 26541294Smckusick if (mntflags & MNT_FORCE) 26641294Smckusick flags |= FORCECLOSE; 267*41398Smckusick nmp = VFSTONFS(mp); 26838414Smckusick /* 26938884Smacklem * Clear out the buffer cache 27038884Smacklem */ 27139669Smckusick mntflushbuf(mp, 0); 27239669Smckusick if (mntinvalbuf(mp)) 27338884Smacklem return (EBUSY); 27438884Smacklem /* 27538414Smckusick * Goes something like this.. 27640120Smckusick * - Check for activity on the root vnode (other than ourselves). 27740120Smckusick * - Call vflush() to clear out vnodes for this file system, 27840120Smckusick * except for the root vnode. 27940120Smckusick * - Decrement reference on the vnode representing remote root. 28038414Smckusick * - Close the socket 28138414Smckusick * - Free up the data structures 28238414Smckusick */ 28340010Smckusick /* 28440010Smckusick * We need to decrement the ref. count on the nfsnode representing 28540010Smckusick * the remote root. See comment in mountnfs(). The VFS unmount() 28640010Smckusick * has done vput on this vnode, otherwise we would get deadlock! 28740010Smckusick */ 28840010Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 28940010Smckusick return(error); 29040120Smckusick vp = NFSTOV(np); 29140120Smckusick if (vp->v_usecount > 2) { 29240120Smckusick vput(vp); 29340120Smckusick return (EBUSY); 29440120Smckusick } 29540120Smckusick if (error = vflush(mp, vp, flags)) { 29640120Smckusick vput(vp); 29740120Smckusick return (error); 29840120Smckusick } 29940010Smckusick /* 30040010Smckusick * Get rid of two reference counts, and unlock it on the second. 30140010Smckusick */ 30240120Smckusick vrele(vp); 30340120Smckusick vput(vp); 30440120Smckusick nfs_disconnect(nmp); 30538414Smckusick free((caddr_t)nmp, M_NFSMNT); 30638414Smckusick return (0); 30738414Smckusick } 30838414Smckusick 30938414Smckusick /* 31038414Smckusick * Return root of a filesystem 31138414Smckusick */ 31238414Smckusick nfs_root(mp, vpp) 31338414Smckusick struct mount *mp; 31438414Smckusick struct vnode **vpp; 31538414Smckusick { 31638414Smckusick register struct vnode *vp; 31738414Smckusick struct nfsmount *nmp; 31838414Smckusick struct nfsnode *np; 31938414Smckusick int error; 32038414Smckusick 321*41398Smckusick nmp = VFSTONFS(mp); 32238414Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 32338414Smckusick return (error); 32438414Smckusick vp = NFSTOV(np); 32538414Smckusick vp->v_type = VDIR; 32638414Smckusick vp->v_flag = VROOT; 32738414Smckusick *vpp = vp; 32838414Smckusick return (0); 32938414Smckusick } 33038414Smckusick 33138884Smacklem extern int syncprt; 33238884Smacklem 33338414Smckusick /* 33438884Smacklem * Flush out the buffer cache 33538414Smckusick */ 33639494Smckusick /* ARGSUSED */ 33738414Smckusick nfs_sync(mp, waitfor) 33838414Smckusick struct mount *mp; 33938414Smckusick int waitfor; 34038414Smckusick { 34138884Smacklem if (syncprt) 34238884Smacklem bufstats(); 34338884Smacklem /* 34438884Smacklem * Force stale buffer cache information to be flushed. 34538884Smacklem */ 34640035Smckusick mntflushbuf(mp, waitfor == MNT_WAIT ? B_SYNC : 0); 34738414Smckusick return (0); 34838414Smckusick } 34938414Smckusick 35038414Smckusick /* 35138414Smckusick * At this point, this should never happen 35238414Smckusick */ 35339494Smckusick /* ARGSUSED */ 35438414Smckusick nfs_fhtovp(mp, fhp, vpp) 35538414Smckusick struct mount *mp; 35638414Smckusick struct fid *fhp; 35738414Smckusick struct vnode **vpp; 35838414Smckusick { 35939494Smckusick 36038414Smckusick return (EINVAL); 36138414Smckusick } 36238414Smckusick 36338414Smckusick /* 36438414Smckusick * Vnode pointer to File handle, should never happen either 36538414Smckusick */ 36639494Smckusick /* ARGSUSED */ 36738414Smckusick nfs_vptofh(mp, fhp, vpp) 36838414Smckusick struct mount *mp; 36938414Smckusick struct fid *fhp; 37038414Smckusick struct vnode **vpp; 37138414Smckusick { 37239494Smckusick 37338414Smckusick return (EINVAL); 37438414Smckusick } 37538884Smacklem 37638884Smacklem /* 37738884Smacklem * Vfs start routine, a no-op. 37838884Smacklem */ 37939494Smckusick /* ARGSUSED */ 38038884Smacklem nfs_start(mp, flags) 38138884Smacklem struct mount *mp; 38238884Smacklem int flags; 38338884Smacklem { 38439494Smckusick 38538884Smacklem return (0); 38638884Smacklem } 38741294Smckusick 38841294Smckusick /* 38941294Smckusick * Do operations associated with quotas, not supported 39041294Smckusick */ 39141294Smckusick /* ARGSUSED */ 39241294Smckusick nfs_quotactl(mp, cmd, uid, arg) 39341294Smckusick struct mount *mp; 39441294Smckusick int cmd; 39541294Smckusick uid_t uid; 39641294Smckusick caddr_t arg; 39741294Smckusick { 39841294Smckusick 39941294Smckusick return (EOPNOTSUPP); 40041294Smckusick } 401