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*39399Smckusick * @(#)nfs_node.c 7.8 (Berkeley) 10/25/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 4939395Smckusick union nhead { 5038415Smckusick union nhead *nh_head[2]; 5138415Smckusick struct nfsnode *nh_chain[2]; 5238415Smckusick } nhead[NFSNOHSZ]; 5338415Smckusick 5438884Smacklem #define TRUE 1 5538884Smacklem #define FALSE 0 5638884Smacklem 5738415Smckusick /* 5838415Smckusick * Initialize hash links for nfsnodes 5938415Smckusick * and build nfsnode free list. 6038415Smckusick */ 6138415Smckusick nfs_nhinit() 6238415Smckusick { 6338415Smckusick register int i; 6438415Smckusick register union nhead *nh = nhead; 6538415Smckusick 6639395Smckusick if (VN_MAXPRIVATE < sizeof(struct nfsnode)) 6739395Smckusick panic("nfs_nhinit: too small"); 6838415Smckusick for (i = NFSNOHSZ; --i >= 0; nh++) { 6938415Smckusick nh->nh_head[0] = nh; 7038415Smckusick nh->nh_head[1] = nh; 7138415Smckusick } 7238415Smckusick } 7338415Smckusick 7438415Smckusick /* 7539395Smckusick * Look up a vnode/nfsnode by file handle. 7638415Smckusick * Callers must check for mount points!! 7738415Smckusick * In all cases, a pointer to a 7838415Smckusick * nfsnode structure is returned. 7938415Smckusick */ 8038415Smckusick nfs_nget(mntp, fhp, npp) 8138415Smckusick struct mount *mntp; 8238415Smckusick register nfsv2fh_t *fhp; 8338415Smckusick struct nfsnode **npp; 8438415Smckusick { 8538415Smckusick register struct nfsnode *np; 8638415Smckusick register struct vnode *vp; 8738415Smckusick register u_char *fhpp; 8838415Smckusick register u_long fhsum; 8939395Smckusick struct vnode *nvp; 9039395Smckusick union nhead *nh; 9139395Smckusick int i, error; 9238415Smckusick 9338415Smckusick fhpp = &fhp->fh_bytes[0]; 9438415Smckusick fhsum = 0; 9538415Smckusick for (i = 0; i < NFSX_FH; i++) 9638415Smckusick fhsum += *fhpp++; 9738415Smckusick loop: 9838415Smckusick nh = &nhead[NFSNOHASH(fhsum)]; 9938884Smacklem for (np = nh->nh_chain[0]; np != (struct nfsnode *)nh; np = np->n_forw) { 10039395Smckusick if (mntp != NFSTOV(np)->v_mount || 10139395Smckusick bcmp((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH)) 10239395Smckusick continue; 10339395Smckusick /* 10439395Smckusick * Following is essentially an inline expanded 10539395Smckusick * copy of ngrab(), expanded inline for speed, 10639395Smckusick * and so that the test for a mounted on nfsnode 10739395Smckusick * can be deferred until after we are sure that 10839395Smckusick * the nfsnode isn't busy. 10939395Smckusick */ 11039395Smckusick if ((np->n_flag & NLOCKED) != 0) { 11139395Smckusick np->n_flag |= NWANT; 11239395Smckusick sleep((caddr_t)np, PINOD); 11339395Smckusick goto loop; 11439395Smckusick } 11539395Smckusick vp = NFSTOV(np); 11639395Smckusick if (vp->v_count == 0) /* nfsnode on free list */ 11739395Smckusick vget(vp); 11839395Smckusick else 11938425Smckusick VREF(vp); 12039395Smckusick np->n_flag |= NLOCKED; 12139395Smckusick *npp = np; 12239395Smckusick return(0); 12338884Smacklem } 12439395Smckusick if (error = getnewvnode(VT_NFS, mntp, &nfsv2_vnodeops, &nvp)) { 12538415Smckusick *npp = 0; 12639395Smckusick return (error); 12738415Smckusick } 12839395Smckusick vp = nvp; 12939395Smckusick np = VTONFS(vp); 13039395Smckusick np->n_vnode = vp; 13138415Smckusick /* 13238884Smacklem * Insert the nfsnode in the hash queue for its new file handle 13338884Smacklem */ 13438884Smacklem np->n_flag = NLOCKED; 13538415Smckusick insque(np, nh); 13638415Smckusick bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH); 13738415Smckusick np->n_attrstamp = 0; 13838415Smckusick np->n_sillyrename = (struct sillyrename *)0; 13938884Smacklem np->n_size = 0; 14038884Smacklem np->n_mtime = 0; 14138415Smckusick /* 14238415Smckusick * Initialize the associated vnode 14338415Smckusick */ 14438415Smckusick *npp = np; 14538415Smckusick return (0); 14638415Smckusick } 14738415Smckusick 14838415Smckusick /* 14938415Smckusick * Convert a pointer to an nfsnode into a reference to an nfsnode. 15038415Smckusick * 15138415Smckusick * This is basically the internal piece of nget (after the 15238415Smckusick * nfsnode pointer is located) but without the test for mounted 15338415Smckusick * filesystems. It is caller's responsibility to check that 15438415Smckusick * the nfsnode pointer is valid. 15538415Smckusick */ 15638415Smckusick nfs_ngrab(np) 15738415Smckusick register struct nfsnode *np; 15838415Smckusick { 15938415Smckusick register struct vnode *vp = NFSTOV(np); 16038415Smckusick 16138415Smckusick while ((np->n_flag & NLOCKED) != 0) { 16238415Smckusick np->n_flag |= NWANT; 16338415Smckusick sleep((caddr_t)np, PINOD); 16438415Smckusick } 16539395Smckusick if (vp->v_count == 0) /* ino on free list */ 16639395Smckusick vget(vp); 16739395Smckusick else 16839395Smckusick VREF(vp); 16938415Smckusick np->n_flag |= NLOCKED; 17038415Smckusick } 17138415Smckusick 17238415Smckusick nfs_inactive(vp) 17338415Smckusick struct vnode *vp; 17438415Smckusick { 17538415Smckusick register struct nfsnode *np; 17638415Smckusick register struct nameidata *ndp; 17738415Smckusick register struct sillyrename *sp; 17838415Smckusick struct nfsnode *dnp; 17938415Smckusick 18039395Smckusick if (vp == NULL || vp->v_count != 0) 18139395Smckusick panic("nfs_inactive: NULL or active vp"); 18239395Smckusick np = VTONFS(vp); 18339395Smckusick nfs_lock(vp); 18439395Smckusick sp = np->n_sillyrename; 18539395Smckusick np->n_sillyrename = (struct sillyrename *)0; 18639395Smckusick if (sp) { 18738415Smckusick /* 18839395Smckusick * Remove the silly file that was rename'd earlier 18938415Smckusick */ 19039395Smckusick ndp = &sp->s_namei; 19139395Smckusick if (!nfs_nget(vp->v_mount, &sp->s_fh, &dnp)) { 19239395Smckusick ndp->ni_dvp = NFSTOV(dnp); 19339395Smckusick nfs_removeit(ndp); 19439395Smckusick nfs_nput(ndp->ni_dvp); 19538415Smckusick } 19639395Smckusick crfree(ndp->ni_cred); 19739395Smckusick free((caddr_t)sp, M_TEMP); 19839395Smckusick } 19939395Smckusick nfs_unlock(vp); 200*39399Smckusick np->n_flag &= NBUFFERED; 20139395Smckusick #ifdef notdef 20239395Smckusick /* 20339395Smckusick * Scan the request list for any requests left hanging about 20439395Smckusick */ 20539395Smckusick s = splnet(); 20639395Smckusick rep = nfsreqh.r_next; 20739395Smckusick while (rep && rep != &nfsreqh) { 20839395Smckusick if (rep->r_vp == vp) { 20939395Smckusick rep->r_prev->r_next = rep2 = rep->r_next; 21039395Smckusick rep->r_next->r_prev = rep->r_prev; 21139395Smckusick m_freem(rep->r_mreq); 21239395Smckusick if (rep->r_mrep != NULL) 21339395Smckusick m_freem(rep->r_mrep); 21439395Smckusick free((caddr_t)rep, M_NFSREQ); 21539395Smckusick rep = rep2; 21639395Smckusick } else 21739395Smckusick rep = rep->r_next; 21839395Smckusick } 21939395Smckusick splx(s); 22038884Smacklem #endif 22139395Smckusick return (0); 22239395Smckusick } 22339395Smckusick 22439395Smckusick /* 22539395Smckusick * Reclaim an nfsnode so that it can be used for other purposes. 22639395Smckusick */ 22739395Smckusick nfs_reclaim(vp) 22839395Smckusick register struct vnode *vp; 22939395Smckusick { 23039395Smckusick register struct nfsnode *np = VTONFS(vp); 23139395Smckusick 23239395Smckusick if (vp->v_count != 0) 23339395Smckusick panic("nfs_reclaim: active inode"); 23439395Smckusick /* 23539395Smckusick * Remove the nfsnode from its hash chain. 23639395Smckusick */ 23739395Smckusick remque(np); 23839395Smckusick np->n_forw = np; 23939395Smckusick np->n_back = np; 24039395Smckusick cache_purge(vp); 24139395Smckusick /* 24239395Smckusick * Flush out any associated bio buffers that might be lying about 24339395Smckusick */ 24439395Smckusick if (vp->v_type == VREG && (np->n_flag & NBUFFERED)) { 24539395Smckusick np->n_flag |= NLOCKED; 24639395Smckusick nfs_blkflush(vp, (daddr_t)0, np->n_size, TRUE); 24738415Smckusick } 24839395Smckusick vp->v_type = VNON; 24938415Smckusick return (0); 25038415Smckusick } 25138415Smckusick 25238415Smckusick /* 25338415Smckusick * Remove any nfsnodes in the nfsnode cache belonging to mount. 25438415Smckusick * 25538415Smckusick * There should not be any active ones, return error if any are found 25638415Smckusick * (nb: this is a user error, not a system err). 25738415Smckusick */ 25838415Smckusick nfs_nflush(mntp) 25938415Smckusick struct mount *mntp; 26038415Smckusick { 26138415Smckusick register struct vnode *vp; 26239395Smckusick int busy = 0; 26338415Smckusick 26439395Smckusick for (vp = mntp->m_mounth; vp; vp = vp->v_mountf) { 26539395Smckusick if (vp->v_count) { 26639395Smckusick busy++; 26739395Smckusick continue; 26839395Smckusick } 26939395Smckusick /* 27039395Smckusick * As v_count == 0, the nfsnode was on the free list already, 27139395Smckusick * so it will fall off the bottom eventually. 27239395Smckusick * We could perhaps move it to the head of the free list, 27339395Smckusick * but as umounts are done so infrequently, we would gain 27439395Smckusick * very little, while making the code bigger. 27539395Smckusick */ 27639395Smckusick nfs_reclaim(vp); 27738415Smckusick } 27839395Smckusick if (busy) 27939395Smckusick return (EBUSY); 28038415Smckusick return (0); 28138415Smckusick } 28238415Smckusick 28338415Smckusick /* 28438415Smckusick * Lock an nfsnode 28538415Smckusick */ 28638415Smckusick nfs_lock(vp) 28738415Smckusick struct vnode *vp; 28838415Smckusick { 28938415Smckusick register struct nfsnode *np = VTONFS(vp); 29038415Smckusick 29138415Smckusick while (np->n_flag & NLOCKED) { 29238415Smckusick np->n_flag |= NWANT; 29338415Smckusick sleep((caddr_t)np, PINOD); 29438415Smckusick } 29538415Smckusick np->n_flag |= NLOCKED; 29638415Smckusick } 29738415Smckusick 29838415Smckusick /* 29938415Smckusick * Unlock an nfsnode 30038415Smckusick */ 30138415Smckusick nfs_unlock(vp) 30238415Smckusick struct vnode *vp; 30338415Smckusick { 30438415Smckusick register struct nfsnode *np = VTONFS(vp); 30538415Smckusick 30638415Smckusick np->n_flag &= ~NLOCKED; 30738415Smckusick if (np->n_flag & NWANT) { 30838415Smckusick np->n_flag &= ~NWANT; 30938415Smckusick wakeup((caddr_t)np); 31038415Smckusick } 31138415Smckusick } 31238415Smckusick 31338415Smckusick /* 31438415Smckusick * Unlock and vrele() 31538415Smckusick * since I can't decide if dirs. should be locked, I will check for 31638415Smckusick * the lock and be flexible 31738415Smckusick */ 31838415Smckusick nfs_nput(vp) 31938415Smckusick struct vnode *vp; 32038415Smckusick { 32138415Smckusick register struct nfsnode *np = VTONFS(vp); 32238415Smckusick 32338415Smckusick if (np->n_flag & NLOCKED) 32438415Smckusick nfs_unlock(vp); 32538415Smckusick vrele(vp); 32638415Smckusick } 32738415Smckusick 32838415Smckusick nfs_abortop(ndp) 32938415Smckusick register struct nameidata *ndp; 33038415Smckusick { 33138415Smckusick register struct nfsnode *np; 33238415Smckusick 33338415Smckusick if (ndp->ni_vp != NULL) { 33438415Smckusick np = VTONFS(ndp->ni_vp); 33538415Smckusick if (np->n_flag & NLOCKED) 33638415Smckusick nfs_unlock(ndp->ni_vp); 33738415Smckusick vrele(ndp->ni_vp); 33838415Smckusick } 33938415Smckusick if (ndp->ni_dvp != NULL) { 34038415Smckusick np = VTONFS(ndp->ni_dvp); 34138415Smckusick if (np->n_flag & NLOCKED) 34238415Smckusick nfs_unlock(ndp->ni_dvp); 34338415Smckusick vrele(ndp->ni_dvp); 34438415Smckusick } 34538415Smckusick } 34638415Smckusick 34738415Smckusick /* 34838415Smckusick * This is silly, but if you use a macro and try and use it in a file 34938415Smckusick * that has mbuf.h included, m_data --> m_hdr.mh_data and this is not 35038415Smckusick * a good thing 35138415Smckusick */ 35238415Smckusick struct nfsmount *vfs_to_nfs(mp) 35338415Smckusick struct mount *mp; 35438415Smckusick { 35538415Smckusick return ((struct nfsmount *)mp->m_data); 35638415Smckusick } 357