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*40035Smckusick * @(#)nfs_vfsops.c 7.13 (Berkeley) 02/08/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" 2939757Smckusick #include "systm.h" 3038425Smckusick #include "../ufs/dir.h" 3138414Smckusick #include "namei.h" 3238414Smckusick #include "vnode.h" 3338414Smckusick #include "mount.h" 3438414Smckusick #include "errno.h" 3538414Smckusick #include "malloc.h" 3638414Smckusick #include "mbuf.h" 3738414Smckusick #undef m_data 3838414Smckusick #include "socket.h" 3938414Smckusick #include "socketvar.h" 4038414Smckusick #include "../netinet/in.h" 4138414Smckusick #include "nfsv2.h" 4238414Smckusick #include "nfsnode.h" 4338414Smckusick #include "nfsmount.h" 4438414Smckusick #include "nfs.h" 4538414Smckusick 4638414Smckusick #ifndef shouldbe 4738414Smckusick #include "conf.h" 4838414Smckusick #endif 4938414Smckusick 5038414Smckusick /* 5138414Smckusick * nfs vfs operations. 5238414Smckusick */ 5338414Smckusick int nfs_mount(); 5438874Smckusick int nfs_start(); 5538414Smckusick int nfs_unmount(); 5638414Smckusick int nfs_root(); 5739443Smckusick int nfs_statfs(); 5838414Smckusick int nfs_sync(); 5938414Smckusick int nfs_fhtovp(); 6038414Smckusick int nfs_vptofh(); 6139443Smckusick int nfs_init(); 6238414Smckusick 6338414Smckusick struct vfsops nfs_vfsops = { 6438414Smckusick nfs_mount, 6538874Smckusick nfs_start, 6638414Smckusick nfs_unmount, 6738414Smckusick nfs_root, 6838414Smckusick nfs_statfs, 6938414Smckusick nfs_sync, 7038414Smckusick nfs_fhtovp, 7138414Smckusick nfs_vptofh, 7239443Smckusick nfs_init, 7338414Smckusick }; 7438414Smckusick 7538414Smckusick extern struct nfsreq nfsreqh; 7639757Smckusick static u_char nfs_mntid; 7738414Smckusick 7838414Smckusick /* 7938414Smckusick * Called by vfs_mountroot when nfs is going to be mounted as root 8038414Smckusick * Not Yet (By a LONG shot) 8138414Smckusick */ 8238414Smckusick nfs_mountroot() 8338414Smckusick { 8438414Smckusick return (ENODEV); 8538414Smckusick } 8638414Smckusick 8738414Smckusick /* 8838414Smckusick * VFS Operations. 8938414Smckusick * 9038414Smckusick * mount system call 9138414Smckusick * It seems a bit dumb to copyinstr() the host and path here and then 9238414Smckusick * bcopy() them in mountnfs(), but I wanted to detect errors before 9338414Smckusick * doing the sockargs() call because sockargs() allocates an mbuf and 9438414Smckusick * an error after that means that I have to release the mbuf. 9538414Smckusick */ 9639494Smckusick /* ARGSUSED */ 9738414Smckusick nfs_mount(mp, path, data, ndp) 9838414Smckusick struct mount *mp; 9938414Smckusick char *path; 10038414Smckusick caddr_t data; 10138414Smckusick struct nameidata *ndp; 10238414Smckusick { 10338414Smckusick int error; 10438414Smckusick struct nfs_args args; 10538414Smckusick struct mbuf *saddr; 10638414Smckusick char pth[MNAMELEN], hst[MNAMELEN]; 10738414Smckusick int len; 10838414Smckusick nfsv2fh_t nfh; 10938414Smckusick 11039460Smckusick if (mp->m_flag & M_UPDATE) 11139460Smckusick return (0); 11238414Smckusick if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args))) 11338414Smckusick return (error); 11438414Smckusick if (error=copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t))) 11538414Smckusick return (error); 11638414Smckusick if (error = copyinstr(path, pth, MNAMELEN-1, &len)) 11738414Smckusick return (error); 11838414Smckusick bzero(&pth[len], MNAMELEN-len); 11938414Smckusick if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len)) 12038414Smckusick return (error); 12138414Smckusick bzero(&hst[len], MNAMELEN-len); 12238414Smckusick /* sockargs() call must be after above copyin() calls */ 12338414Smckusick if (error = sockargs(&saddr, (caddr_t)args.addr, 12438414Smckusick sizeof (struct sockaddr_in), MT_SONAME)) 12538414Smckusick return (error); 12638414Smckusick args.fh = &nfh; 12738414Smckusick error = mountnfs(&args, mp, saddr, pth, hst); 12838414Smckusick return (error); 12938414Smckusick } 13038414Smckusick 13138414Smckusick /* 13238414Smckusick * Common code for mount and mountroot 13338414Smckusick */ 13438414Smckusick mountnfs(argp, mp, saddr, pth, hst) 13538414Smckusick register struct nfs_args *argp; 13638414Smckusick register struct mount *mp; 13738414Smckusick register struct mbuf *saddr; 13838414Smckusick char *pth, *hst; 13938414Smckusick { 14038414Smckusick register struct nfsmount *nmp; 14140010Smckusick struct nfsnode *np; 14239757Smckusick fsid_t tfsid; 14338414Smckusick int error; 14438414Smckusick 14538414Smckusick nmp = (struct nfsmount *)malloc(sizeof (struct nfsmount), M_NFSMNT, 14638414Smckusick M_WAITOK); 14738414Smckusick mp->m_data = (qaddr_t)nmp; 14839757Smckusick /* 14939757Smckusick * Generate a unique nfs mount id. The problem is that a dev number 15039757Smckusick * is not unique across multiple systems. The techique is as follows: 15139757Smckusick * 1) Set to nblkdev,0 which will never be used otherwise 15239757Smckusick * 2) Generate a first guess as nblkdev,nfs_mntid where nfs_mntid is 15339757Smckusick * NOT 0 15439757Smckusick * 3) Loop searching the mount list for another one with same id 15539757Smckusick * If a match, increment val[0] and try again 15639757Smckusick * NB: I increment val[0] { a long } instead of nfs_mntid { a u_char } 15739757Smckusick * so that nfs is not limited to 255 mount points 15839757Smckusick * Incrementing the high order bits does no real harm, since it 15939757Smckusick * simply makes the major dev number tick up. The upper bound is 16039757Smckusick * set to major dev 127 to avoid any sign extention problems 16139757Smckusick */ 16239757Smckusick mp->m_fsid.val[0] = makedev(nblkdev, 0); 16338414Smckusick mp->m_fsid.val[1] = MOUNT_NFS; 16439757Smckusick if (++nfs_mntid == 0) 16539757Smckusick ++nfs_mntid; 16639757Smckusick tfsid.val[0] = makedev(nblkdev, nfs_mntid); 16739757Smckusick tfsid.val[1] = MOUNT_NFS; 16839757Smckusick while (getvfs(&tfsid)) { 16939757Smckusick tfsid.val[0]++; 17039757Smckusick nfs_mntid++; 17139757Smckusick } 17239757Smckusick if (major(tfsid.val[0]) > 127) { 17339757Smckusick error = ENOENT; 17439757Smckusick goto bad; 17539757Smckusick } 17639757Smckusick mp->m_fsid.val[0] = tfsid.val[0]; 17738414Smckusick nmp->nm_mountp = mp; 17838414Smckusick nmp->nm_flag = argp->flags; 17938414Smckusick nmp->nm_sockaddr = saddr; 18038414Smckusick /* Set up the sockets */ 18138414Smckusick if (error = socreate(AF_INET, &nmp->nm_so, SOCK_DGRAM, 0)) 18238414Smckusick goto bad; 18338414Smckusick if (error = soconnect(nmp->nm_so, saddr)) 18438414Smckusick goto bad; 18538414Smckusick if ((argp->flags & NFSMNT_TIMEO) && argp->timeo >= 1) 18638414Smckusick nmp->nm_timeo = argp->timeo; 18738414Smckusick else 18838414Smckusick nmp->nm_timeo = NFS_TIMEO; 18938414Smckusick if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 0) 19038414Smckusick nmp->nm_retrans = argp->retrans; 19138414Smckusick else 19238414Smckusick nmp->nm_retrans = NFS_RETRANS; 19338414Smckusick if ((argp->flags & NFSMNT_WSIZE) && 19438414Smckusick argp->wsize <= NFS_MAXDATA && argp->wsize > 0 && 19538414Smckusick (argp->wsize & 0x1ff) == 0) 19638414Smckusick nmp->nm_wsize = argp->wsize; 19738414Smckusick else 19838414Smckusick nmp->nm_wsize = NFS_WSIZE; 19938414Smckusick if ((argp->flags & NFSMNT_RSIZE) && 20038414Smckusick argp->rsize <= NFS_MAXDATA && argp->rsize > 0 && 20138414Smckusick (argp->rsize & 0x1ff) == 0) 20238414Smckusick nmp->nm_rsize = argp->rsize; 20338414Smckusick else 20438414Smckusick nmp->nm_rsize = NFS_RSIZE; 20538414Smckusick bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t)); 20638414Smckusick bcopy(pth, nmp->nm_path, MNAMELEN); 20738414Smckusick bcopy(hst, nmp->nm_host, MNAMELEN); 20838414Smckusick /* 20938425Smckusick * Set to CLBYTES so that vinifod() doesn't get confused. 21038425Smckusick * Actually any exact multiple of CLBYTES will do 21138425Smckusick */ 21238425Smckusick mp->m_bsize = mp->m_fsize = CLBYTES; 21340010Smckusick /* 21440010Smckusick * A reference count is needed on the nfsnode representing the 21540010Smckusick * remote root. If this object is not persistent, then backward 21640010Smckusick * traversals of the mount point (i.e. "..") will not work if 21740010Smckusick * the nfsnode gets flushed out of the cache. Ufs does not have 21840010Smckusick * this problem, because one can identify root inodes by their 21940010Smckusick * number == ROOTINO (2). 22040010Smckusick */ 22140010Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 22240010Smckusick goto bad; 22340010Smckusick /* 22440010Smckusick * Unlock it, but keep the reference count. 22540010Smckusick */ 22640010Smckusick nfs_unlock(NFSTOV(np)); 22738414Smckusick return (0); 22838414Smckusick bad: 22938414Smckusick m_freem(saddr); 23038414Smckusick free((caddr_t)nmp, M_NFSMNT); 23138414Smckusick return (error); 23238414Smckusick } 23338414Smckusick 23438414Smckusick /* 23538414Smckusick * unmount system call 23638414Smckusick */ 23738414Smckusick nfs_unmount(mp, flags) 23838414Smckusick struct mount *mp; 23938414Smckusick int flags; 24038414Smckusick { 24138414Smckusick register struct nfsmount *nmp; 24238414Smckusick register struct nfsreq *rep; 24338414Smckusick struct nfsreq *rep2; 24440010Smckusick struct nfsnode *np; 24538414Smckusick int error; 24638414Smckusick int s; 24738414Smckusick 24838414Smckusick if (flags & MNT_FORCE) 24938414Smckusick return (EINVAL); 25038414Smckusick nmp = vfs_to_nfs(mp); 25138414Smckusick /* 25238884Smacklem * Clear out the buffer cache 25338884Smacklem */ 25439669Smckusick mntflushbuf(mp, 0); 25539669Smckusick if (mntinvalbuf(mp)) 25638884Smacklem return (EBUSY); 25738884Smacklem /* 25838414Smckusick * Goes something like this.. 25940010Smckusick * - Decrement reference on the nfsnode representing remote root. 26040010Smckusick * Must do this first, otherwise vflush will return EBUSY. 26139510Smckusick * - Call vflush() to clear out vnodes for this file system 26238414Smckusick * - Flush out lookup cache 26338414Smckusick * - Close the socket 26438414Smckusick * - Free up the data structures 26538414Smckusick */ 26640010Smckusick /* 26740010Smckusick * We need to decrement the ref. count on the nfsnode representing 26840010Smckusick * the remote root. See comment in mountnfs(). The VFS unmount() 26940010Smckusick * has done vput on this vnode, otherwise we would get deadlock! 27040010Smckusick */ 27140010Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 27240010Smckusick return(error); 27340010Smckusick /* 27440010Smckusick * Get rid of two reference counts, and unlock it on the second. 27540010Smckusick */ 27640010Smckusick vrele(NFSTOV(np)); 27740010Smckusick vput(NFSTOV(np)); 27839510Smckusick if (error = vflush(mp, (struct vnode *)0, flags)) 27938414Smckusick return (error); 28038414Smckusick /* 28138414Smckusick * Scan the request list for any requests left hanging about 28238414Smckusick */ 28338414Smckusick s = splnet(); 28438414Smckusick rep = nfsreqh.r_next; 28539347Smckusick while (rep && rep != &nfsreqh) { 28638414Smckusick if (rep->r_mntp == nmp) { 28738414Smckusick rep->r_prev->r_next = rep2 = rep->r_next; 28839347Smckusick rep->r_next->r_prev = rep->r_prev; 28938414Smckusick m_freem(rep->r_mreq); 29038414Smckusick if (rep->r_mrep != NULL) 29138414Smckusick m_freem(rep->r_mrep); 29238414Smckusick free((caddr_t)rep, M_NFSREQ); 29338414Smckusick rep = rep2; 29438414Smckusick } else 29538414Smckusick rep = rep->r_next; 29638414Smckusick } 29738414Smckusick splx(s); 29838414Smckusick soclose(nmp->nm_so); 29938414Smckusick m_freem(nmp->nm_sockaddr); 30038414Smckusick free((caddr_t)nmp, M_NFSMNT); 30138414Smckusick return (0); 30238414Smckusick } 30338414Smckusick 30438414Smckusick /* 30538414Smckusick * Return root of a filesystem 30638414Smckusick */ 30738414Smckusick nfs_root(mp, vpp) 30838414Smckusick struct mount *mp; 30938414Smckusick struct vnode **vpp; 31038414Smckusick { 31138414Smckusick register struct vnode *vp; 31238414Smckusick struct nfsmount *nmp; 31338414Smckusick struct nfsnode *np; 31438414Smckusick int error; 31538414Smckusick 31638414Smckusick nmp = vfs_to_nfs(mp); 31738414Smckusick if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 31838414Smckusick return (error); 31938414Smckusick vp = NFSTOV(np); 32038414Smckusick vp->v_type = VDIR; 32138414Smckusick vp->v_flag = VROOT; 32238414Smckusick *vpp = vp; 32338414Smckusick return (0); 32438414Smckusick } 32538414Smckusick 32638884Smacklem extern int syncprt; 32738884Smacklem 32838414Smckusick /* 32938884Smacklem * Flush out the buffer cache 33038414Smckusick */ 33139494Smckusick /* ARGSUSED */ 33238414Smckusick nfs_sync(mp, waitfor) 33338414Smckusick struct mount *mp; 33438414Smckusick int waitfor; 33538414Smckusick { 33638884Smacklem if (syncprt) 33738884Smacklem bufstats(); 33838884Smacklem /* 33938884Smacklem * Force stale buffer cache information to be flushed. 34038884Smacklem */ 341*40035Smckusick mntflushbuf(mp, waitfor == MNT_WAIT ? B_SYNC : 0); 34238414Smckusick return (0); 34338414Smckusick } 34438414Smckusick 34538414Smckusick /* 34638414Smckusick * At this point, this should never happen 34738414Smckusick */ 34839494Smckusick /* ARGSUSED */ 34938414Smckusick nfs_fhtovp(mp, fhp, vpp) 35038414Smckusick struct mount *mp; 35138414Smckusick struct fid *fhp; 35238414Smckusick struct vnode **vpp; 35338414Smckusick { 35439494Smckusick 35538414Smckusick return (EINVAL); 35638414Smckusick } 35738414Smckusick 35838414Smckusick /* 35938414Smckusick * Vnode pointer to File handle, should never happen either 36038414Smckusick */ 36139494Smckusick /* ARGSUSED */ 36238414Smckusick nfs_vptofh(mp, fhp, vpp) 36338414Smckusick struct mount *mp; 36438414Smckusick struct fid *fhp; 36538414Smckusick struct vnode **vpp; 36638414Smckusick { 36739494Smckusick 36838414Smckusick return (EINVAL); 36938414Smckusick } 37038884Smacklem 37138884Smacklem /* 37238884Smacklem * Vfs start routine, a no-op. 37338884Smacklem */ 37439494Smckusick /* ARGSUSED */ 37538884Smacklem nfs_start(mp, flags) 37638884Smacklem struct mount *mp; 37738884Smacklem int flags; 37838884Smacklem { 37939494Smckusick 38038884Smacklem return (0); 38138884Smacklem } 382