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*38884Smacklem * @(#)nfs_node.c 7.4 (Berkeley) 08/30/89 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" 2938425Smckusick #include "../ufs/dir.h" 3038415Smckusick #include "namei.h" 3138415Smckusick #include "errno.h" 3238415Smckusick #include "nfsv2.h" 3338415Smckusick #include "nfs.h" 3438415Smckusick #include "nfsnode.h" 3538415Smckusick #include "nfsmount.h" 3638415Smckusick #include "kernel.h" 3738415Smckusick #include "malloc.h" 3838415Smckusick 3938415Smckusick /* The request list head */ 4038415Smckusick extern struct nfsreq nfsreqh; 4138415Smckusick 4238415Smckusick #define NFSNOHSZ 512 4338415Smckusick #if ((NFSNOHSZ&(NFSNOHSZ-1)) == 0) 4438415Smckusick #define NFSNOHASH(fhsum) ((fhsum)&(NFSNOHSZ-1)) 4538415Smckusick #else 4638415Smckusick #define NFSNOHASH(fhsum) (((unsigned)(fhsum))%NFSNOHSZ) 4738415Smckusick #endif 4838415Smckusick 4938415Smckusick union nhead { /* inode LRU cache, Chris Maltby */ 5038415Smckusick union nhead *nh_head[2]; 5138415Smckusick struct nfsnode *nh_chain[2]; 5238415Smckusick } nhead[NFSNOHSZ]; 5338415Smckusick 5438415Smckusick struct nfsnode *nfreeh, **nfreet; 5538415Smckusick 56*38884Smacklem #define TRUE 1 57*38884Smacklem #define FALSE 0 58*38884Smacklem 5938415Smckusick /* 6038415Smckusick * Initialize hash links for nfsnodes 6138415Smckusick * and build nfsnode free list. 6238415Smckusick */ 6338415Smckusick nfs_nhinit() 6438415Smckusick { 6538415Smckusick register int i; 6638415Smckusick register struct nfsnode *np = nfsnode; 6738415Smckusick register union nhead *nh = nhead; 6838415Smckusick 6938415Smckusick for (i = NFSNOHSZ; --i >= 0; nh++) { 7038415Smckusick nh->nh_head[0] = nh; 7138415Smckusick nh->nh_head[1] = nh; 7238415Smckusick } 7338415Smckusick nfreeh = np; 7438415Smckusick nfreet = &np->n_freef; 7538415Smckusick np->n_freeb = &nfreeh; 7638415Smckusick np->n_forw = np; 7738415Smckusick np->n_back = np; 7838415Smckusick NFSTOV(np)->v_data = (qaddr_t)np; 79*38884Smacklem NFSTOV(np)->v_type = VNON; 8038415Smckusick for (i = nnfsnode; --i > 0; ) { 8138415Smckusick ++np; 8238415Smckusick np->n_forw = np; 8338415Smckusick np->n_back = np; 8438415Smckusick NFSTOV(np)->v_data = (qaddr_t)np; 85*38884Smacklem NFSTOV(np)->v_type = VNON; 8638415Smckusick *nfreet = np; 8738415Smckusick np->n_freeb = nfreet; 8838415Smckusick nfreet = &np->n_freef; 8938415Smckusick } 9038415Smckusick np->n_freef = NULL; 9138415Smckusick } 9238415Smckusick 9338415Smckusick /* 9438415Smckusick * Look up an vnode/nfsnode by file handle. 9538415Smckusick * Callers must check for mount points!! 9638415Smckusick * In all cases, a pointer to a 9738415Smckusick * nfsnode structure is returned. 9838415Smckusick */ 9938415Smckusick nfs_nget(mntp, fhp, npp) 10038415Smckusick struct mount *mntp; 10138415Smckusick register nfsv2fh_t *fhp; 10238415Smckusick struct nfsnode **npp; 10338415Smckusick { 10438415Smckusick register struct nfsnode *np; 10538415Smckusick register struct vnode *vp; 10638415Smckusick register struct nfsnode *nq; 10738415Smckusick register u_char *fhpp; 10838415Smckusick register u_long fhsum; 10938415Smckusick register int i; 11038415Smckusick union nhead *nh; 11138415Smckusick int error; 11238415Smckusick 11338415Smckusick fhpp = &fhp->fh_bytes[0]; 11438415Smckusick fhsum = 0; 11538415Smckusick for (i = 0; i < NFSX_FH; i++) 11638415Smckusick fhsum += *fhpp++; 11738415Smckusick loop: 11838415Smckusick nh = &nhead[NFSNOHASH(fhsum)]; 119*38884Smacklem for (np = nh->nh_chain[0]; np != (struct nfsnode *)nh; np = np->n_forw) { 12038415Smckusick if (mntp == NFSTOV(np)->v_mount && 12138415Smckusick !bcmp((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH)) { 12238415Smckusick /* 12338415Smckusick * Following is essentially an inline expanded 12438415Smckusick * copy of ngrab(), expanded inline for speed, 12538415Smckusick * and so that the test for a mounted on nfsnode 12638415Smckusick * can be deferred until after we are sure that 12738415Smckusick * the nfsnode isn't busy. 12838415Smckusick */ 12938415Smckusick if ((np->n_flag & NLOCKED) != 0) { 13038415Smckusick np->n_flag |= NWANT; 13138415Smckusick sleep((caddr_t)np, PINOD); 13238415Smckusick goto loop; 13338415Smckusick } 13438415Smckusick vp = NFSTOV(np); 13538415Smckusick if (vp->v_count == 0) { /* nfsno on free list */ 13638415Smckusick if (nq = np->n_freef) 13738415Smckusick nq->n_freeb = np->n_freeb; 13838415Smckusick else 13938415Smckusick nfreet = np->n_freeb; 14038415Smckusick *np->n_freeb = nq; 14138415Smckusick np->n_freef = NULL; 14238415Smckusick np->n_freeb = NULL; 14338415Smckusick } 14438415Smckusick np->n_flag |= NLOCKED; 14538425Smckusick VREF(vp); 14638415Smckusick *npp = np; 14738415Smckusick return(0); 14838415Smckusick } 14938415Smckusick 150*38884Smacklem } 15138415Smckusick if ((np = nfreeh) == NULL) { 15238415Smckusick tablefull("nfsnode"); 15338415Smckusick *npp = 0; 15438415Smckusick return(ENFILE); 15538415Smckusick } 15638415Smckusick vp = NFSTOV(np); 15738415Smckusick if (vp->v_count) 15838415Smckusick panic("free nfsnode isn't"); 15938415Smckusick if (nq = np->n_freef) 16038415Smckusick nq->n_freeb = &nfreeh; 16138415Smckusick nfreeh = nq; 16238415Smckusick np->n_freef = NULL; 16338415Smckusick np->n_freeb = NULL; 16438415Smckusick /* 16538415Smckusick * Now to take nfsnode off the hash chain it was on 16638415Smckusick * (initially, or after an nflush, it is on a "hash chain" 16738415Smckusick * consisting entirely of itself, and pointed to by no-one, 168*38884Smacklem * but that doesn't matter) 16938415Smckusick */ 17038415Smckusick remque(np); 171*38884Smacklem /* 172*38884Smacklem * Flush out any associated bio buffers that might be lying about 173*38884Smacklem */ 174*38884Smacklem if (vp->v_type == VREG && (np->n_flag & NMODIFIED) == 0) { 175*38884Smacklem np->n_flag |= NLOCKED; 176*38884Smacklem nfs_blkflush(vp, (daddr_t)0, np->n_size, TRUE); 177*38884Smacklem } 178*38884Smacklem /* 179*38884Smacklem * Insert the nfsnode in the hash queue for its new file handle 180*38884Smacklem */ 181*38884Smacklem np->n_flag = NLOCKED; 18238415Smckusick insque(np, nh); 18338415Smckusick bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH); 184*38884Smacklem #ifndef notyet 18538415Smckusick cache_purge(vp); 18638415Smckusick #endif 18738415Smckusick np->n_attrstamp = 0; 18838415Smckusick np->n_sillyrename = (struct sillyrename *)0; 18938415Smckusick np->n_id = ++nextnfsnodeid; 190*38884Smacklem np->n_size = 0; 191*38884Smacklem np->n_mtime = 0; 19238415Smckusick /* 19338415Smckusick * Initialize the associated vnode 19438415Smckusick */ 19538415Smckusick vinit(vp, mntp, VNON, &nfsv2_vnodeops); 19638415Smckusick *npp = np; 19738415Smckusick return (0); 19838415Smckusick } 19938415Smckusick 20038415Smckusick /* 20138415Smckusick * Convert a pointer to an nfsnode into a reference to an nfsnode. 20238415Smckusick * 20338415Smckusick * This is basically the internal piece of nget (after the 20438415Smckusick * nfsnode pointer is located) but without the test for mounted 20538415Smckusick * filesystems. It is caller's responsibility to check that 20638415Smckusick * the nfsnode pointer is valid. 20738415Smckusick */ 20838415Smckusick nfs_ngrab(np) 20938415Smckusick register struct nfsnode *np; 21038415Smckusick { 21138415Smckusick register struct vnode *vp = NFSTOV(np); 21238415Smckusick 21338415Smckusick while ((np->n_flag & NLOCKED) != 0) { 21438415Smckusick np->n_flag |= NWANT; 21538415Smckusick sleep((caddr_t)np, PINOD); 21638415Smckusick } 21738415Smckusick if (vp->v_count == 0) { /* ino on free list */ 21838415Smckusick register struct nfsnode *nq; 21938415Smckusick 22038415Smckusick if (nq = np->n_freef) 22138415Smckusick nq->n_freeb = np->n_freeb; 22238415Smckusick else 22338415Smckusick nfreet = np->n_freeb; 22438415Smckusick *np->n_freeb = nq; 22538415Smckusick np->n_freef = NULL; 22638415Smckusick np->n_freeb = NULL; 22738415Smckusick } 22838425Smckusick VREF(vp); 22938415Smckusick np->n_flag |= NLOCKED; 23038415Smckusick } 23138415Smckusick 23238415Smckusick nfs_inactive(vp) 23338415Smckusick struct vnode *vp; 23438415Smckusick { 23538415Smckusick register struct nfsnode *np; 23638415Smckusick register struct nameidata *ndp; 23738415Smckusick register struct sillyrename *sp; 23838415Smckusick register struct nfsreq *rep; 23938415Smckusick struct nfsreq *rep2; 24038415Smckusick struct nfsnode *dnp; 24138415Smckusick int s; 24238415Smckusick 24338415Smckusick if (vp == NULL) 24438415Smckusick panic("nfs_inactive NULL vp"); 24538415Smckusick if (vp->v_count == 0) { 24638415Smckusick np = VTONFS(vp); 247*38884Smacklem sp = np->n_sillyrename; 248*38884Smacklem np->n_sillyrename = (struct sillyrename *)0; 249*38884Smacklem nfs_lock(vp); 250*38884Smacklem if (sp) { 251*38884Smacklem printf("in silltren inact\n"); 25238415Smckusick /* 25338415Smckusick * Remove the silly file that was rename'd earlier 25438415Smckusick */ 25538415Smckusick ndp = &sp->s_namei; 25638415Smckusick if (!nfs_nget(vp->v_mount, &sp->s_fh, &dnp)) { 257*38884Smacklem printf("got the dir\n"); 25838415Smckusick ndp->ni_dvp = NFSTOV(dnp); 259*38884Smacklem nfs_removeit(ndp); 26038415Smckusick nfs_nput(ndp->ni_dvp); 26138415Smckusick } 26238415Smckusick crfree(ndp->ni_cred); 26338415Smckusick free((caddr_t)sp, M_TEMP); 26438415Smckusick } 26538415Smckusick nfs_unlock(vp); 26638415Smckusick np->n_flag = 0; 267*38884Smacklem #ifdef notdef 26838415Smckusick /* 26938415Smckusick * Scan the request list for any requests left hanging about 27038415Smckusick */ 27138415Smckusick s = splnet(); 27238415Smckusick rep = nfsreqh.r_next; 27338415Smckusick while (rep) { 27438415Smckusick if (rep->r_vp == vp) { 27538415Smckusick rep->r_prev->r_next = rep2 = rep->r_next; 27638415Smckusick if (rep->r_next != NULL) 27738415Smckusick rep->r_next->r_prev = rep->r_prev; 27838415Smckusick m_freem(rep->r_mreq); 27938415Smckusick if (rep->r_mrep != NULL) 28038415Smckusick m_freem(rep->r_mrep); 28138415Smckusick free((caddr_t)rep, M_NFSREQ); 28238415Smckusick rep = rep2; 28338415Smckusick } else 28438415Smckusick rep = rep->r_next; 28538415Smckusick } 28638415Smckusick splx(s); 287*38884Smacklem #endif 28838415Smckusick /* 28938415Smckusick * Put the nfsnode on the end of the free list. 29038415Smckusick */ 29138415Smckusick if (nfreeh) { 29238415Smckusick *nfreet = np; 29338415Smckusick np->n_freeb = nfreet; 29438415Smckusick } else { 29538415Smckusick nfreeh = np; 29638415Smckusick np->n_freeb = &nfreeh; 29738415Smckusick } 29838415Smckusick np->n_freef = NULL; 29938415Smckusick nfreet = &np->n_freef; 30038415Smckusick } 30138415Smckusick return (0); 30238415Smckusick } 30338415Smckusick 30438415Smckusick /* 30538415Smckusick * Remove any nfsnodes in the nfsnode cache belonging to mount. 30638415Smckusick * 30738415Smckusick * There should not be any active ones, return error if any are found 30838415Smckusick * (nb: this is a user error, not a system err). 30938415Smckusick */ 31038415Smckusick nfs_nflush(mntp) 31138415Smckusick struct mount *mntp; 31238415Smckusick { 31338415Smckusick register struct nfsnode *np; 31438415Smckusick register struct vnode *vp; 31538415Smckusick 31638415Smckusick for (np = nfsnode; np < nfsnodeNNFSNODE; np++) { 31738415Smckusick vp = NFSTOV(np); 31838415Smckusick if (vp->v_mount == mntp) 31938415Smckusick if (vp->v_count) 32038415Smckusick return (EBUSY); 32138415Smckusick else { 32238415Smckusick remque(np); 32338415Smckusick np->n_forw = np; 32438415Smckusick np->n_back = np; 32538415Smckusick /* 32638415Smckusick * as v_count == 0, the inode was on the free 32738415Smckusick * list already, just leave it there, it will 32838415Smckusick * fall off the bottom eventually. We could 32938415Smckusick * perhaps move it to the head of the free 33038415Smckusick * list, but as umounts are done so 33138415Smckusick * infrequently, we would gain very little, 33238415Smckusick * while making the code bigger. 33338415Smckusick */ 33438415Smckusick } 33538415Smckusick } 33638415Smckusick return (0); 33738415Smckusick } 33838415Smckusick 33938415Smckusick /* 34038415Smckusick * Lock an nfsnode 34138415Smckusick */ 34238415Smckusick nfs_lock(vp) 34338415Smckusick struct vnode *vp; 34438415Smckusick { 34538415Smckusick register struct nfsnode *np = VTONFS(vp); 34638415Smckusick 34738415Smckusick if (np->n_flag & NLOCKED) 34838415Smckusick printf("pid %d hit locked nfsnode=0x%x\n", 34938415Smckusick u.u_procp->p_pid, np); 35038415Smckusick while (np->n_flag & NLOCKED) { 35138415Smckusick np->n_flag |= NWANT; 35238415Smckusick sleep((caddr_t)np, PINOD); 35338415Smckusick } 35438415Smckusick np->n_flag |= NLOCKED; 35538415Smckusick } 35638415Smckusick 35738415Smckusick /* 35838415Smckusick * Unlock an nfsnode 35938415Smckusick */ 36038415Smckusick nfs_unlock(vp) 36138415Smckusick struct vnode *vp; 36238415Smckusick { 36338415Smckusick register struct nfsnode *np = VTONFS(vp); 36438415Smckusick 36538415Smckusick if ((np->n_flag & NLOCKED) == 0) { 36638415Smckusick printf("pid %d unlocking unlocked nfsnode=0x%x ", 36738415Smckusick u.u_procp->p_pid, np); 36838415Smckusick printf("fh0=0x%x fh1=0x%x fh2=0x%x fh3=0x%x fh4=0x%x fh5=0x%x fh6=0x%x fh7=0x%x\n", 36938415Smckusick np->n_fh.fh_bytes[0],np->n_fh.fh_bytes[1], 37038415Smckusick np->n_fh.fh_bytes[2],np->n_fh.fh_bytes[3], 37138415Smckusick np->n_fh.fh_bytes[4],np->n_fh.fh_bytes[5], 37238415Smckusick np->n_fh.fh_bytes[6],np->n_fh.fh_bytes[7]); 37338415Smckusick } 37438415Smckusick np->n_flag &= ~NLOCKED; 37538415Smckusick if (np->n_flag & NWANT) { 37638415Smckusick np->n_flag &= ~NWANT; 37738415Smckusick wakeup((caddr_t)np); 37838415Smckusick } 37938415Smckusick } 38038415Smckusick 38138415Smckusick /* 38238415Smckusick * Unlock and vrele() 38338415Smckusick * since I can't decide if dirs. should be locked, I will check for 38438415Smckusick * the lock and be flexible 38538415Smckusick */ 38638415Smckusick nfs_nput(vp) 38738415Smckusick struct vnode *vp; 38838415Smckusick { 38938415Smckusick register struct nfsnode *np = VTONFS(vp); 39038415Smckusick 39138415Smckusick if (np->n_flag & NLOCKED) 39238415Smckusick nfs_unlock(vp); 39338415Smckusick vrele(vp); 39438415Smckusick } 39538415Smckusick 39638415Smckusick nfs_abortop(ndp) 39738415Smckusick register struct nameidata *ndp; 39838415Smckusick { 39938415Smckusick register struct nfsnode *np; 40038415Smckusick 40138415Smckusick if (ndp->ni_vp != NULL) { 40238415Smckusick np = VTONFS(ndp->ni_vp); 40338415Smckusick if (np->n_flag & NLOCKED) 40438415Smckusick nfs_unlock(ndp->ni_vp); 40538415Smckusick vrele(ndp->ni_vp); 40638415Smckusick } 40738415Smckusick if (ndp->ni_dvp != NULL) { 40838415Smckusick np = VTONFS(ndp->ni_dvp); 40938415Smckusick if (np->n_flag & NLOCKED) 41038415Smckusick nfs_unlock(ndp->ni_dvp); 41138415Smckusick vrele(ndp->ni_dvp); 41238415Smckusick } 41338415Smckusick } 41438415Smckusick 41538415Smckusick /* 41638415Smckusick * This is silly, but if you use a macro and try and use it in a file 41738415Smckusick * that has mbuf.h included, m_data --> m_hdr.mh_data and this is not 41838415Smckusick * a good thing 41938415Smckusick */ 42038415Smckusick struct nfsmount *vfs_to_nfs(mp) 42138415Smckusick struct mount *mp; 42238415Smckusick { 42338415Smckusick return ((struct nfsmount *)mp->m_data); 42438415Smckusick } 425