138415Smckusick /* 238415Smckusick * Copyright (c) 1989 The Regents of the University of California. 338415Smckusick * All rights reserved. 438415Smckusick * 538415Smckusick * This code is derived from software contributed to Berkeley by 638415Smckusick * Rick Macklem at The University of Guelph. 738415Smckusick * 838415Smckusick * Redistribution and use in source and binary forms are permitted 938415Smckusick * provided that the above copyright notice and this paragraph are 1038415Smckusick * duplicated in all such forms and that any documentation, 1138415Smckusick * advertising materials, and other materials related to such 1238415Smckusick * distribution and use acknowledge that the software was developed 1338415Smckusick * by the University of California, Berkeley. The name of the 1438415Smckusick * University may not be used to endorse or promote products derived 1538415Smckusick * from this software without specific prior written permission. 1638415Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1738415Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1838415Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1938415Smckusick * 20*43349Smckusick * @(#)nfs_node.c 7.28 (Berkeley) 06/21/90 2138415Smckusick */ 2238415Smckusick 2338415Smckusick #include "param.h" 2438415Smckusick #include "systm.h" 2538415Smckusick #include "user.h" 2638415Smckusick #include "proc.h" 2738415Smckusick #include "mount.h" 2838415Smckusick #include "vnode.h" 2938415Smckusick #include "errno.h" 3038415Smckusick #include "nfsv2.h" 3138415Smckusick #include "nfs.h" 3238415Smckusick #include "nfsnode.h" 3338415Smckusick #include "nfsmount.h" 3438415Smckusick #include "kernel.h" 3538415Smckusick #include "malloc.h" 3638415Smckusick 3738415Smckusick /* The request list head */ 3838415Smckusick extern struct nfsreq nfsreqh; 3938415Smckusick 4038415Smckusick #define NFSNOHSZ 512 4138415Smckusick #if ((NFSNOHSZ&(NFSNOHSZ-1)) == 0) 4238415Smckusick #define NFSNOHASH(fhsum) ((fhsum)&(NFSNOHSZ-1)) 4338415Smckusick #else 4438415Smckusick #define NFSNOHASH(fhsum) (((unsigned)(fhsum))%NFSNOHSZ) 4538415Smckusick #endif 4638415Smckusick 4739395Smckusick union nhead { 4838415Smckusick union nhead *nh_head[2]; 4938415Smckusick struct nfsnode *nh_chain[2]; 5038415Smckusick } nhead[NFSNOHSZ]; 5138415Smckusick 5238884Smacklem #define TRUE 1 5338884Smacklem #define FALSE 0 5438884Smacklem 5538415Smckusick /* 5638415Smckusick * Initialize hash links for nfsnodes 5738415Smckusick * and build nfsnode free list. 5838415Smckusick */ 5938415Smckusick nfs_nhinit() 6038415Smckusick { 6138415Smckusick register int i; 6238415Smckusick register union nhead *nh = nhead; 6338415Smckusick 6439494Smckusick #ifndef lint 6539395Smckusick if (VN_MAXPRIVATE < sizeof(struct nfsnode)) 6639395Smckusick panic("nfs_nhinit: too small"); 6739494Smckusick #endif /* not lint */ 6838415Smckusick for (i = NFSNOHSZ; --i >= 0; nh++) { 6938415Smckusick nh->nh_head[0] = nh; 7038415Smckusick nh->nh_head[1] = nh; 7138415Smckusick } 7238415Smckusick } 7338415Smckusick 7438415Smckusick /* 7539445Smckusick * Compute an entry in the NFS hash table structure 7639445Smckusick */ 7739445Smckusick union nhead * 7839445Smckusick nfs_hash(fhp) 7939445Smckusick register nfsv2fh_t *fhp; 8039445Smckusick { 8139445Smckusick register u_char *fhpp; 8239445Smckusick register u_long fhsum; 8339445Smckusick int i; 8439445Smckusick 8539445Smckusick fhpp = &fhp->fh_bytes[0]; 8639445Smckusick fhsum = 0; 8739445Smckusick for (i = 0; i < NFSX_FH; i++) 8839445Smckusick fhsum += *fhpp++; 8939445Smckusick return (&nhead[NFSNOHASH(fhsum)]); 9039445Smckusick } 9139445Smckusick 9239445Smckusick /* 9339395Smckusick * Look up a vnode/nfsnode by file handle. 9438415Smckusick * Callers must check for mount points!! 9538415Smckusick * In all cases, a pointer to a 9638415Smckusick * nfsnode structure is returned. 9738415Smckusick */ 9838415Smckusick nfs_nget(mntp, fhp, npp) 9938415Smckusick struct mount *mntp; 10038415Smckusick register nfsv2fh_t *fhp; 10138415Smckusick struct nfsnode **npp; 10238415Smckusick { 10338415Smckusick register struct nfsnode *np; 10438415Smckusick register struct vnode *vp; 10539445Smckusick extern struct vnodeops nfsv2_vnodeops; 10639395Smckusick struct vnode *nvp; 10739395Smckusick union nhead *nh; 10839445Smckusick int error; 10938415Smckusick 11039445Smckusick nh = nfs_hash(fhp); 11138415Smckusick loop: 11238884Smacklem for (np = nh->nh_chain[0]; np != (struct nfsnode *)nh; np = np->n_forw) { 11339395Smckusick if (mntp != NFSTOV(np)->v_mount || 11439395Smckusick bcmp((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH)) 11539395Smckusick continue; 11639395Smckusick if ((np->n_flag & NLOCKED) != 0) { 11739395Smckusick np->n_flag |= NWANT; 118*43349Smckusick (void) tsleep((caddr_t)np, PINOD, "nfsnode", 0); 11939395Smckusick goto loop; 12039395Smckusick } 12139395Smckusick vp = NFSTOV(np); 12239445Smckusick if (vget(vp)) 12339445Smckusick goto loop; 12439395Smckusick *npp = np; 12539395Smckusick return(0); 12638884Smacklem } 12739395Smckusick if (error = getnewvnode(VT_NFS, mntp, &nfsv2_vnodeops, &nvp)) { 12838415Smckusick *npp = 0; 12939395Smckusick return (error); 13038415Smckusick } 13139395Smckusick vp = nvp; 13239395Smckusick np = VTONFS(vp); 13339395Smckusick np->n_vnode = vp; 13438415Smckusick /* 13538884Smacklem * Insert the nfsnode in the hash queue for its new file handle 13638884Smacklem */ 13739908Smckusick np->n_flag = 0; 13838415Smckusick insque(np, nh); 13939908Smckusick nfs_lock(vp); 14038415Smckusick bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH); 14138415Smckusick np->n_attrstamp = 0; 14241898Smckusick np->n_direofoffset = 0; 14338415Smckusick np->n_sillyrename = (struct sillyrename *)0; 14438884Smacklem np->n_size = 0; 14538884Smacklem np->n_mtime = 0; 14638415Smckusick *npp = np; 14738415Smckusick return (0); 14838415Smckusick } 14938415Smckusick 15038415Smckusick nfs_inactive(vp) 15138415Smckusick struct vnode *vp; 15238415Smckusick { 15338415Smckusick register struct nfsnode *np; 15438415Smckusick register struct nameidata *ndp; 15538415Smckusick register struct sillyrename *sp; 15638415Smckusick struct nfsnode *dnp; 15739575Smckusick extern int prtactive; 15838415Smckusick 15939395Smckusick np = VTONFS(vp); 16039810Smckusick if (prtactive && vp->v_usecount != 0) 16139671Smckusick vprint("nfs_inactive: pushing active", vp); 16239395Smckusick nfs_lock(vp); 16339395Smckusick sp = np->n_sillyrename; 16439395Smckusick np->n_sillyrename = (struct sillyrename *)0; 16539395Smckusick if (sp) { 16638415Smckusick /* 16739395Smckusick * Remove the silly file that was rename'd earlier 16838415Smckusick */ 16939395Smckusick ndp = &sp->s_namei; 17039395Smckusick if (!nfs_nget(vp->v_mount, &sp->s_fh, &dnp)) { 17139395Smckusick ndp->ni_dvp = NFSTOV(dnp); 17239395Smckusick nfs_removeit(ndp); 17339395Smckusick nfs_nput(ndp->ni_dvp); 17438415Smckusick } 17539395Smckusick crfree(ndp->ni_cred); 17639395Smckusick free((caddr_t)sp, M_TEMP); 17739395Smckusick } 17839395Smckusick nfs_unlock(vp); 17941898Smckusick np->n_flag &= NMODIFIED; 18039395Smckusick #ifdef notdef 18139395Smckusick /* 18239395Smckusick * Scan the request list for any requests left hanging about 18339395Smckusick */ 18439395Smckusick s = splnet(); 18539395Smckusick rep = nfsreqh.r_next; 18639395Smckusick while (rep && rep != &nfsreqh) { 18739395Smckusick if (rep->r_vp == vp) { 18839395Smckusick rep->r_prev->r_next = rep2 = rep->r_next; 18939395Smckusick rep->r_next->r_prev = rep->r_prev; 19039395Smckusick m_freem(rep->r_mreq); 19139395Smckusick if (rep->r_mrep != NULL) 19239395Smckusick m_freem(rep->r_mrep); 19339395Smckusick free((caddr_t)rep, M_NFSREQ); 19439395Smckusick rep = rep2; 19539395Smckusick } else 19639395Smckusick rep = rep->r_next; 19739395Smckusick } 19839395Smckusick splx(s); 19938884Smacklem #endif 20039395Smckusick return (0); 20139395Smckusick } 20239395Smckusick 20339395Smckusick /* 20439395Smckusick * Reclaim an nfsnode so that it can be used for other purposes. 20539395Smckusick */ 20639395Smckusick nfs_reclaim(vp) 20739395Smckusick register struct vnode *vp; 20839395Smckusick { 20939395Smckusick register struct nfsnode *np = VTONFS(vp); 21039575Smckusick extern int prtactive; 21139395Smckusick 21239810Smckusick if (prtactive && vp->v_usecount != 0) 21339671Smckusick vprint("nfs_reclaim: pushing active", vp); 21439395Smckusick /* 21539395Smckusick * Remove the nfsnode from its hash chain. 21639395Smckusick */ 21739395Smckusick remque(np); 21839395Smckusick np->n_forw = np; 21939395Smckusick np->n_back = np; 22039395Smckusick cache_purge(vp); 22139752Smckusick np->n_flag = 0; 22241898Smckusick np->n_direofoffset = 0; 22338415Smckusick return (0); 22438415Smckusick } 22538415Smckusick 22638415Smckusick /* 22738415Smckusick * Lock an nfsnode 22838415Smckusick */ 22938415Smckusick nfs_lock(vp) 23038415Smckusick struct vnode *vp; 23138415Smckusick { 23238415Smckusick register struct nfsnode *np = VTONFS(vp); 23338415Smckusick 23438415Smckusick while (np->n_flag & NLOCKED) { 23538415Smckusick np->n_flag |= NWANT; 23639904Smckusick if (np->n_lockholder == u.u_procp->p_pid) 23739904Smckusick panic("locking against myself"); 23839904Smckusick np->n_lockwaiter = u.u_procp->p_pid; 239*43349Smckusick (void) tsleep((caddr_t)np, PINOD, "nfslock", 0); 24038415Smckusick } 24139904Smckusick np->n_lockwaiter = 0; 24239904Smckusick np->n_lockholder = u.u_procp->p_pid; 24339904Smckusick u.u_spare[0]++; 24438415Smckusick np->n_flag |= NLOCKED; 24538415Smckusick } 24638415Smckusick 24738415Smckusick /* 24838415Smckusick * Unlock an nfsnode 24938415Smckusick */ 25038415Smckusick nfs_unlock(vp) 25138415Smckusick struct vnode *vp; 25238415Smckusick { 25338415Smckusick register struct nfsnode *np = VTONFS(vp); 25438415Smckusick 25539904Smckusick if ((np->n_flag & NLOCKED) == 0) 25639904Smckusick vprint("nfs_unlock: unlocked nfsnode", vp); 25739904Smckusick np->n_lockholder = 0; 25839904Smckusick u.u_spare[0]--; 25938415Smckusick np->n_flag &= ~NLOCKED; 26038415Smckusick if (np->n_flag & NWANT) { 26138415Smckusick np->n_flag &= ~NWANT; 26238415Smckusick wakeup((caddr_t)np); 26338415Smckusick } 26438415Smckusick } 26538415Smckusick 26638415Smckusick /* 26739908Smckusick * Check for a locked nfsnode 26839908Smckusick */ 26939908Smckusick nfs_islocked(vp) 27039908Smckusick struct vnode *vp; 27139908Smckusick { 27239908Smckusick 27339908Smckusick if (VTONFS(vp)->n_flag & NLOCKED) 27439908Smckusick return (1); 27539908Smckusick return (0); 27639908Smckusick } 27739908Smckusick 27839908Smckusick /* 27938415Smckusick * Unlock and vrele() 28038415Smckusick * since I can't decide if dirs. should be locked, I will check for 28138415Smckusick * the lock and be flexible 28238415Smckusick */ 28338415Smckusick nfs_nput(vp) 28438415Smckusick struct vnode *vp; 28538415Smckusick { 28638415Smckusick register struct nfsnode *np = VTONFS(vp); 28738415Smckusick 28838415Smckusick if (np->n_flag & NLOCKED) 28938415Smckusick nfs_unlock(vp); 29038415Smckusick vrele(vp); 29138415Smckusick } 29238415Smckusick 29342467Smckusick /* 29442467Smckusick * Nfs abort op, called after namei() when a CREATE/DELETE isn't actually 29542467Smckusick * done. Currently nothing to do. 29642467Smckusick */ 29742467Smckusick /* ARGSUSED */ 29838415Smckusick nfs_abortop(ndp) 29942467Smckusick struct nameidata *ndp; 30038415Smckusick { 30138415Smckusick 30242467Smckusick return (0); 30338415Smckusick } 304