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*51985Smckusick * @(#)nfs_node.c 7.35 (Berkeley) 12/16/91 1138415Smckusick */ 1238415Smckusick 1338415Smckusick #include "param.h" 1438415Smckusick #include "systm.h" 1538415Smckusick #include "proc.h" 1638415Smckusick #include "mount.h" 1748052Smckusick #include "namei.h" 1838415Smckusick #include "vnode.h" 1947573Skarels #include "kernel.h" 2047573Skarels #include "malloc.h" 2147573Skarels 2238415Smckusick #include "nfsv2.h" 2338415Smckusick #include "nfs.h" 2438415Smckusick #include "nfsnode.h" 2538415Smckusick #include "nfsmount.h" 2638415Smckusick 2738415Smckusick /* The request list head */ 2838415Smckusick extern struct nfsreq nfsreqh; 2938415Smckusick 3038415Smckusick #define NFSNOHSZ 512 3138415Smckusick #if ((NFSNOHSZ&(NFSNOHSZ-1)) == 0) 3238415Smckusick #define NFSNOHASH(fhsum) ((fhsum)&(NFSNOHSZ-1)) 3338415Smckusick #else 3438415Smckusick #define NFSNOHASH(fhsum) (((unsigned)(fhsum))%NFSNOHSZ) 3538415Smckusick #endif 3638415Smckusick 3739395Smckusick union nhead { 3838415Smckusick union nhead *nh_head[2]; 3938415Smckusick struct nfsnode *nh_chain[2]; 4038415Smckusick } nhead[NFSNOHSZ]; 4138415Smckusick 4238884Smacklem #define TRUE 1 4338884Smacklem #define FALSE 0 4438884Smacklem 4538415Smckusick /* 4638415Smckusick * Initialize hash links for nfsnodes 4738415Smckusick * and build nfsnode free list. 4838415Smckusick */ 4938415Smckusick nfs_nhinit() 5038415Smckusick { 5138415Smckusick register int i; 5238415Smckusick register union nhead *nh = nhead; 5338415Smckusick 5439494Smckusick #ifndef lint 55*51985Smckusick if ((sizeof(struct nfsnode) - 1) & sizeof(struct nfsnode)) 56*51985Smckusick printf("nfs_nhinit: bad size %d\n", sizeof(struct nfsnode)); 5739494Smckusick #endif /* not lint */ 5838415Smckusick for (i = NFSNOHSZ; --i >= 0; nh++) { 5938415Smckusick nh->nh_head[0] = nh; 6038415Smckusick nh->nh_head[1] = nh; 6138415Smckusick } 6238415Smckusick } 6338415Smckusick 6438415Smckusick /* 6539445Smckusick * Compute an entry in the NFS hash table structure 6639445Smckusick */ 6739445Smckusick union nhead * 6839445Smckusick nfs_hash(fhp) 6939445Smckusick register nfsv2fh_t *fhp; 7039445Smckusick { 7139445Smckusick register u_char *fhpp; 7239445Smckusick register u_long fhsum; 7339445Smckusick int i; 7439445Smckusick 7539445Smckusick fhpp = &fhp->fh_bytes[0]; 7639445Smckusick fhsum = 0; 7739445Smckusick for (i = 0; i < NFSX_FH; i++) 7839445Smckusick fhsum += *fhpp++; 7939445Smckusick return (&nhead[NFSNOHASH(fhsum)]); 8039445Smckusick } 8139445Smckusick 8239445Smckusick /* 8339395Smckusick * Look up a vnode/nfsnode by file handle. 8438415Smckusick * Callers must check for mount points!! 8538415Smckusick * In all cases, a pointer to a 8638415Smckusick * nfsnode structure is returned. 8738415Smckusick */ 8838415Smckusick nfs_nget(mntp, fhp, npp) 8938415Smckusick struct mount *mntp; 9038415Smckusick register nfsv2fh_t *fhp; 9138415Smckusick struct nfsnode **npp; 9238415Smckusick { 9338415Smckusick register struct nfsnode *np; 9438415Smckusick register struct vnode *vp; 9539445Smckusick extern struct vnodeops nfsv2_vnodeops; 9639395Smckusick struct vnode *nvp; 9739395Smckusick union nhead *nh; 9839445Smckusick int error; 9938415Smckusick 10039445Smckusick nh = nfs_hash(fhp); 10138415Smckusick loop: 10238884Smacklem for (np = nh->nh_chain[0]; np != (struct nfsnode *)nh; np = np->n_forw) { 10339395Smckusick if (mntp != NFSTOV(np)->v_mount || 10439395Smckusick bcmp((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH)) 10539395Smckusick continue; 10639395Smckusick if ((np->n_flag & NLOCKED) != 0) { 10739395Smckusick np->n_flag |= NWANT; 10843349Smckusick (void) tsleep((caddr_t)np, PINOD, "nfsnode", 0); 10939395Smckusick goto loop; 11039395Smckusick } 11139395Smckusick vp = NFSTOV(np); 11239445Smckusick if (vget(vp)) 11339445Smckusick goto loop; 11439395Smckusick *npp = np; 11539395Smckusick return(0); 11638884Smacklem } 11739395Smckusick if (error = getnewvnode(VT_NFS, mntp, &nfsv2_vnodeops, &nvp)) { 11838415Smckusick *npp = 0; 11939395Smckusick return (error); 12038415Smckusick } 12139395Smckusick vp = nvp; 122*51985Smckusick MALLOC(np, struct nfsnode *, sizeof *np, M_NFSNODE, M_WAITOK); 123*51985Smckusick vp->v_data = np; 12439395Smckusick np->n_vnode = vp; 12538415Smckusick /* 12638884Smacklem * Insert the nfsnode in the hash queue for its new file handle 12738884Smacklem */ 12839908Smckusick np->n_flag = 0; 12938415Smckusick insque(np, nh); 13039908Smckusick nfs_lock(vp); 13138415Smckusick bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH); 13238415Smckusick np->n_attrstamp = 0; 13341898Smckusick np->n_direofoffset = 0; 13438415Smckusick np->n_sillyrename = (struct sillyrename *)0; 13538884Smacklem np->n_size = 0; 13638884Smacklem np->n_mtime = 0; 13738415Smckusick *npp = np; 13838415Smckusick return (0); 13938415Smckusick } 14038415Smckusick 14148052Smckusick nfs_inactive(vp, p) 14238415Smckusick struct vnode *vp; 14348052Smckusick struct proc *p; 14438415Smckusick { 14538415Smckusick register struct nfsnode *np; 14638415Smckusick register struct sillyrename *sp; 14738415Smckusick struct nfsnode *dnp; 14839575Smckusick extern int prtactive; 14938415Smckusick 15039395Smckusick np = VTONFS(vp); 15139810Smckusick if (prtactive && vp->v_usecount != 0) 15239671Smckusick vprint("nfs_inactive: pushing active", vp); 15339395Smckusick nfs_lock(vp); 15439395Smckusick sp = np->n_sillyrename; 15539395Smckusick np->n_sillyrename = (struct sillyrename *)0; 15639395Smckusick if (sp) { 15738415Smckusick /* 15839395Smckusick * Remove the silly file that was rename'd earlier 15938415Smckusick */ 16039395Smckusick if (!nfs_nget(vp->v_mount, &sp->s_fh, &dnp)) { 16148364Smckusick sp->s_dvp = NFSTOV(dnp); 16248364Smckusick nfs_removeit(sp, p); 16348364Smckusick nfs_nput(sp->s_dvp); 16438415Smckusick } 16548364Smckusick crfree(sp->s_cred); 16648364Smckusick vrele(sp->s_dvp); 167*51985Smckusick #ifdef SILLYSEPARATE 16848364Smckusick free((caddr_t)sp, M_NFSREQ); 169*51985Smckusick #endif 17039395Smckusick } 17139395Smckusick nfs_unlock(vp); 17241898Smckusick np->n_flag &= NMODIFIED; 17339395Smckusick #ifdef notdef 17439395Smckusick /* 17539395Smckusick * Scan the request list for any requests left hanging about 17639395Smckusick */ 17739395Smckusick s = splnet(); 17839395Smckusick rep = nfsreqh.r_next; 17939395Smckusick while (rep && rep != &nfsreqh) { 18039395Smckusick if (rep->r_vp == vp) { 18139395Smckusick rep->r_prev->r_next = rep2 = rep->r_next; 18239395Smckusick rep->r_next->r_prev = rep->r_prev; 18339395Smckusick m_freem(rep->r_mreq); 18439395Smckusick if (rep->r_mrep != NULL) 18539395Smckusick m_freem(rep->r_mrep); 18639395Smckusick free((caddr_t)rep, M_NFSREQ); 18739395Smckusick rep = rep2; 18839395Smckusick } else 18939395Smckusick rep = rep->r_next; 19039395Smckusick } 19139395Smckusick splx(s); 19238884Smacklem #endif 19339395Smckusick return (0); 19439395Smckusick } 19539395Smckusick 19639395Smckusick /* 19739395Smckusick * Reclaim an nfsnode so that it can be used for other purposes. 19839395Smckusick */ 19939395Smckusick nfs_reclaim(vp) 20039395Smckusick register struct vnode *vp; 20139395Smckusick { 20239395Smckusick register struct nfsnode *np = VTONFS(vp); 20339575Smckusick extern int prtactive; 20439395Smckusick 20539810Smckusick if (prtactive && vp->v_usecount != 0) 20639671Smckusick vprint("nfs_reclaim: pushing active", vp); 20739395Smckusick /* 20839395Smckusick * Remove the nfsnode from its hash chain. 20939395Smckusick */ 21039395Smckusick remque(np); 21139395Smckusick cache_purge(vp); 212*51985Smckusick FREE(vp->v_data, M_NFSNODE); 213*51985Smckusick vp->v_data = NULL; 21438415Smckusick return (0); 21538415Smckusick } 21638415Smckusick 21738415Smckusick /* 21849462Smckusick * In theory, NFS does not need locking, but we make provision 21949462Smckusick * for doing it just in case it is needed. 22049462Smckusick */ 22149462Smckusick int donfslocking = 0; 22249462Smckusick /* 22338415Smckusick * Lock an nfsnode 22438415Smckusick */ 22549462Smckusick 22638415Smckusick nfs_lock(vp) 22738415Smckusick struct vnode *vp; 22838415Smckusick { 22938415Smckusick register struct nfsnode *np = VTONFS(vp); 23038415Smckusick 23149462Smckusick if (!donfslocking) 23249462Smckusick return; 23338415Smckusick while (np->n_flag & NLOCKED) { 23438415Smckusick np->n_flag |= NWANT; 23547573Skarels if (np->n_lockholder == curproc->p_pid) 23639904Smckusick panic("locking against myself"); 23747573Skarels np->n_lockwaiter = curproc->p_pid; 23843349Smckusick (void) tsleep((caddr_t)np, PINOD, "nfslock", 0); 23938415Smckusick } 24039904Smckusick np->n_lockwaiter = 0; 24147573Skarels np->n_lockholder = curproc->p_pid; 24238415Smckusick np->n_flag |= NLOCKED; 24338415Smckusick } 24438415Smckusick 24538415Smckusick /* 24638415Smckusick * Unlock an nfsnode 24738415Smckusick */ 24838415Smckusick nfs_unlock(vp) 24938415Smckusick struct vnode *vp; 25038415Smckusick { 25138415Smckusick register struct nfsnode *np = VTONFS(vp); 25238415Smckusick 25339904Smckusick np->n_lockholder = 0; 25438415Smckusick np->n_flag &= ~NLOCKED; 25538415Smckusick if (np->n_flag & NWANT) { 25638415Smckusick np->n_flag &= ~NWANT; 25738415Smckusick wakeup((caddr_t)np); 25838415Smckusick } 25938415Smckusick } 26038415Smckusick 26138415Smckusick /* 26239908Smckusick * Check for a locked nfsnode 26339908Smckusick */ 26439908Smckusick nfs_islocked(vp) 26539908Smckusick struct vnode *vp; 26639908Smckusick { 26739908Smckusick 26839908Smckusick if (VTONFS(vp)->n_flag & NLOCKED) 26939908Smckusick return (1); 27039908Smckusick return (0); 27139908Smckusick } 27239908Smckusick 27339908Smckusick /* 27438415Smckusick * Unlock and vrele() 27538415Smckusick * since I can't decide if dirs. should be locked, I will check for 27638415Smckusick * the lock and be flexible 27738415Smckusick */ 27838415Smckusick nfs_nput(vp) 27938415Smckusick struct vnode *vp; 28038415Smckusick { 28138415Smckusick register struct nfsnode *np = VTONFS(vp); 28238415Smckusick 28338415Smckusick if (np->n_flag & NLOCKED) 28438415Smckusick nfs_unlock(vp); 28538415Smckusick vrele(vp); 28638415Smckusick } 28738415Smckusick 28842467Smckusick /* 28942467Smckusick * Nfs abort op, called after namei() when a CREATE/DELETE isn't actually 29042467Smckusick * done. Currently nothing to do. 29142467Smckusick */ 29242467Smckusick /* ARGSUSED */ 29338415Smckusick nfs_abortop(ndp) 29442467Smckusick struct nameidata *ndp; 29538415Smckusick { 29638415Smckusick 29749740Smckusick if ((ndp->ni_nameiop & (HASBUF | SAVESTART)) == HASBUF) 29849740Smckusick FREE(ndp->ni_pnbuf, M_NAMEI); 29942467Smckusick return (0); 30038415Smckusick } 301