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 * 844509Sbostic * %sccs.include.redist.c% 938415Smckusick * 10*47573Skarels * @(#)nfs_node.c 7.30 (Berkeley) 03/19/91 1138415Smckusick */ 1238415Smckusick 1338415Smckusick #include "param.h" 1438415Smckusick #include "systm.h" 1538415Smckusick #include "proc.h" 1638415Smckusick #include "mount.h" 1738415Smckusick #include "vnode.h" 18*47573Skarels #include "kernel.h" 19*47573Skarels #include "malloc.h" 20*47573Skarels 2138415Smckusick #include "nfsv2.h" 2238415Smckusick #include "nfs.h" 2338415Smckusick #include "nfsnode.h" 2438415Smckusick #include "nfsmount.h" 2538415Smckusick 2638415Smckusick /* The request list head */ 2738415Smckusick extern struct nfsreq nfsreqh; 2838415Smckusick 2938415Smckusick #define NFSNOHSZ 512 3038415Smckusick #if ((NFSNOHSZ&(NFSNOHSZ-1)) == 0) 3138415Smckusick #define NFSNOHASH(fhsum) ((fhsum)&(NFSNOHSZ-1)) 3238415Smckusick #else 3338415Smckusick #define NFSNOHASH(fhsum) (((unsigned)(fhsum))%NFSNOHSZ) 3438415Smckusick #endif 3538415Smckusick 3639395Smckusick union nhead { 3738415Smckusick union nhead *nh_head[2]; 3838415Smckusick struct nfsnode *nh_chain[2]; 3938415Smckusick } nhead[NFSNOHSZ]; 4038415Smckusick 4138884Smacklem #define TRUE 1 4238884Smacklem #define FALSE 0 4338884Smacklem 4438415Smckusick /* 4538415Smckusick * Initialize hash links for nfsnodes 4638415Smckusick * and build nfsnode free list. 4738415Smckusick */ 4838415Smckusick nfs_nhinit() 4938415Smckusick { 5038415Smckusick register int i; 5138415Smckusick register union nhead *nh = nhead; 5238415Smckusick 5339494Smckusick #ifndef lint 5439395Smckusick if (VN_MAXPRIVATE < sizeof(struct nfsnode)) 5539395Smckusick panic("nfs_nhinit: too small"); 5639494Smckusick #endif /* not lint */ 5738415Smckusick for (i = NFSNOHSZ; --i >= 0; nh++) { 5838415Smckusick nh->nh_head[0] = nh; 5938415Smckusick nh->nh_head[1] = nh; 6038415Smckusick } 6138415Smckusick } 6238415Smckusick 6338415Smckusick /* 6439445Smckusick * Compute an entry in the NFS hash table structure 6539445Smckusick */ 6639445Smckusick union nhead * 6739445Smckusick nfs_hash(fhp) 6839445Smckusick register nfsv2fh_t *fhp; 6939445Smckusick { 7039445Smckusick register u_char *fhpp; 7139445Smckusick register u_long fhsum; 7239445Smckusick int i; 7339445Smckusick 7439445Smckusick fhpp = &fhp->fh_bytes[0]; 7539445Smckusick fhsum = 0; 7639445Smckusick for (i = 0; i < NFSX_FH; i++) 7739445Smckusick fhsum += *fhpp++; 7839445Smckusick return (&nhead[NFSNOHASH(fhsum)]); 7939445Smckusick } 8039445Smckusick 8139445Smckusick /* 8239395Smckusick * Look up a vnode/nfsnode by file handle. 8338415Smckusick * Callers must check for mount points!! 8438415Smckusick * In all cases, a pointer to a 8538415Smckusick * nfsnode structure is returned. 8638415Smckusick */ 8738415Smckusick nfs_nget(mntp, fhp, npp) 8838415Smckusick struct mount *mntp; 8938415Smckusick register nfsv2fh_t *fhp; 9038415Smckusick struct nfsnode **npp; 9138415Smckusick { 9238415Smckusick register struct nfsnode *np; 9338415Smckusick register struct vnode *vp; 9439445Smckusick extern struct vnodeops nfsv2_vnodeops; 9539395Smckusick struct vnode *nvp; 9639395Smckusick union nhead *nh; 9739445Smckusick int error; 9838415Smckusick 9939445Smckusick nh = nfs_hash(fhp); 10038415Smckusick loop: 10138884Smacklem for (np = nh->nh_chain[0]; np != (struct nfsnode *)nh; np = np->n_forw) { 10239395Smckusick if (mntp != NFSTOV(np)->v_mount || 10339395Smckusick bcmp((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH)) 10439395Smckusick continue; 10539395Smckusick if ((np->n_flag & NLOCKED) != 0) { 10639395Smckusick np->n_flag |= NWANT; 10743349Smckusick (void) tsleep((caddr_t)np, PINOD, "nfsnode", 0); 10839395Smckusick goto loop; 10939395Smckusick } 11039395Smckusick vp = NFSTOV(np); 11139445Smckusick if (vget(vp)) 11239445Smckusick goto loop; 11339395Smckusick *npp = np; 11439395Smckusick return(0); 11538884Smacklem } 11639395Smckusick if (error = getnewvnode(VT_NFS, mntp, &nfsv2_vnodeops, &nvp)) { 11738415Smckusick *npp = 0; 11839395Smckusick return (error); 11938415Smckusick } 12039395Smckusick vp = nvp; 12139395Smckusick np = VTONFS(vp); 12239395Smckusick np->n_vnode = vp; 12338415Smckusick /* 12438884Smacklem * Insert the nfsnode in the hash queue for its new file handle 12538884Smacklem */ 12639908Smckusick np->n_flag = 0; 12738415Smckusick insque(np, nh); 12839908Smckusick nfs_lock(vp); 12938415Smckusick bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH); 13038415Smckusick np->n_attrstamp = 0; 13141898Smckusick np->n_direofoffset = 0; 13238415Smckusick np->n_sillyrename = (struct sillyrename *)0; 13338884Smacklem np->n_size = 0; 13438884Smacklem np->n_mtime = 0; 13538415Smckusick *npp = np; 13638415Smckusick return (0); 13738415Smckusick } 13838415Smckusick 13938415Smckusick nfs_inactive(vp) 14038415Smckusick struct vnode *vp; 14138415Smckusick { 14238415Smckusick register struct nfsnode *np; 14338415Smckusick register struct nameidata *ndp; 14438415Smckusick register struct sillyrename *sp; 14538415Smckusick struct nfsnode *dnp; 14639575Smckusick extern int prtactive; 14738415Smckusick 14839395Smckusick np = VTONFS(vp); 14939810Smckusick if (prtactive && vp->v_usecount != 0) 15039671Smckusick vprint("nfs_inactive: pushing active", vp); 15139395Smckusick nfs_lock(vp); 15239395Smckusick sp = np->n_sillyrename; 15339395Smckusick np->n_sillyrename = (struct sillyrename *)0; 15439395Smckusick if (sp) { 15538415Smckusick /* 15639395Smckusick * Remove the silly file that was rename'd earlier 15738415Smckusick */ 15839395Smckusick ndp = &sp->s_namei; 15939395Smckusick if (!nfs_nget(vp->v_mount, &sp->s_fh, &dnp)) { 16039395Smckusick ndp->ni_dvp = NFSTOV(dnp); 16139395Smckusick nfs_removeit(ndp); 16239395Smckusick nfs_nput(ndp->ni_dvp); 16338415Smckusick } 16439395Smckusick crfree(ndp->ni_cred); 16539395Smckusick free((caddr_t)sp, M_TEMP); 16639395Smckusick } 16739395Smckusick nfs_unlock(vp); 16841898Smckusick np->n_flag &= NMODIFIED; 16939395Smckusick #ifdef notdef 17039395Smckusick /* 17139395Smckusick * Scan the request list for any requests left hanging about 17239395Smckusick */ 17339395Smckusick s = splnet(); 17439395Smckusick rep = nfsreqh.r_next; 17539395Smckusick while (rep && rep != &nfsreqh) { 17639395Smckusick if (rep->r_vp == vp) { 17739395Smckusick rep->r_prev->r_next = rep2 = rep->r_next; 17839395Smckusick rep->r_next->r_prev = rep->r_prev; 17939395Smckusick m_freem(rep->r_mreq); 18039395Smckusick if (rep->r_mrep != NULL) 18139395Smckusick m_freem(rep->r_mrep); 18239395Smckusick free((caddr_t)rep, M_NFSREQ); 18339395Smckusick rep = rep2; 18439395Smckusick } else 18539395Smckusick rep = rep->r_next; 18639395Smckusick } 18739395Smckusick splx(s); 18838884Smacklem #endif 18939395Smckusick return (0); 19039395Smckusick } 19139395Smckusick 19239395Smckusick /* 19339395Smckusick * Reclaim an nfsnode so that it can be used for other purposes. 19439395Smckusick */ 19539395Smckusick nfs_reclaim(vp) 19639395Smckusick register struct vnode *vp; 19739395Smckusick { 19839395Smckusick register struct nfsnode *np = VTONFS(vp); 19939575Smckusick extern int prtactive; 20039395Smckusick 20139810Smckusick if (prtactive && vp->v_usecount != 0) 20239671Smckusick vprint("nfs_reclaim: pushing active", vp); 20339395Smckusick /* 20439395Smckusick * Remove the nfsnode from its hash chain. 20539395Smckusick */ 20639395Smckusick remque(np); 20739395Smckusick np->n_forw = np; 20839395Smckusick np->n_back = np; 20939395Smckusick cache_purge(vp); 21039752Smckusick np->n_flag = 0; 21141898Smckusick np->n_direofoffset = 0; 21238415Smckusick return (0); 21338415Smckusick } 21438415Smckusick 21538415Smckusick /* 21638415Smckusick * Lock an nfsnode 21738415Smckusick */ 21838415Smckusick nfs_lock(vp) 21938415Smckusick struct vnode *vp; 22038415Smckusick { 22138415Smckusick register struct nfsnode *np = VTONFS(vp); 22238415Smckusick 22338415Smckusick while (np->n_flag & NLOCKED) { 22438415Smckusick np->n_flag |= NWANT; 225*47573Skarels if (np->n_lockholder == curproc->p_pid) 22639904Smckusick panic("locking against myself"); 227*47573Skarels np->n_lockwaiter = curproc->p_pid; 22843349Smckusick (void) tsleep((caddr_t)np, PINOD, "nfslock", 0); 22938415Smckusick } 23039904Smckusick np->n_lockwaiter = 0; 231*47573Skarels np->n_lockholder = curproc->p_pid; 23238415Smckusick np->n_flag |= NLOCKED; 23338415Smckusick } 23438415Smckusick 23538415Smckusick /* 23638415Smckusick * Unlock an nfsnode 23738415Smckusick */ 23838415Smckusick nfs_unlock(vp) 23938415Smckusick struct vnode *vp; 24038415Smckusick { 24138415Smckusick register struct nfsnode *np = VTONFS(vp); 24238415Smckusick 24339904Smckusick if ((np->n_flag & NLOCKED) == 0) 24439904Smckusick vprint("nfs_unlock: unlocked nfsnode", vp); 24539904Smckusick np->n_lockholder = 0; 24638415Smckusick np->n_flag &= ~NLOCKED; 24738415Smckusick if (np->n_flag & NWANT) { 24838415Smckusick np->n_flag &= ~NWANT; 24938415Smckusick wakeup((caddr_t)np); 25038415Smckusick } 25138415Smckusick } 25238415Smckusick 25338415Smckusick /* 25439908Smckusick * Check for a locked nfsnode 25539908Smckusick */ 25639908Smckusick nfs_islocked(vp) 25739908Smckusick struct vnode *vp; 25839908Smckusick { 25939908Smckusick 26039908Smckusick if (VTONFS(vp)->n_flag & NLOCKED) 26139908Smckusick return (1); 26239908Smckusick return (0); 26339908Smckusick } 26439908Smckusick 26539908Smckusick /* 26638415Smckusick * Unlock and vrele() 26738415Smckusick * since I can't decide if dirs. should be locked, I will check for 26838415Smckusick * the lock and be flexible 26938415Smckusick */ 27038415Smckusick nfs_nput(vp) 27138415Smckusick struct vnode *vp; 27238415Smckusick { 27338415Smckusick register struct nfsnode *np = VTONFS(vp); 27438415Smckusick 27538415Smckusick if (np->n_flag & NLOCKED) 27638415Smckusick nfs_unlock(vp); 27738415Smckusick vrele(vp); 27838415Smckusick } 27938415Smckusick 28042467Smckusick /* 28142467Smckusick * Nfs abort op, called after namei() when a CREATE/DELETE isn't actually 28242467Smckusick * done. Currently nothing to do. 28342467Smckusick */ 28442467Smckusick /* ARGSUSED */ 28538415Smckusick nfs_abortop(ndp) 28642467Smckusick struct nameidata *ndp; 28738415Smckusick { 28838415Smckusick 28942467Smckusick return (0); 29038415Smckusick } 291