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*39395Smckusick * @(#)nfs_node.c 7.7 (Berkeley) 10/24/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 49*39395Smckusick 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 66*39395Smckusick if (VN_MAXPRIVATE < sizeof(struct nfsnode)) 67*39395Smckusick 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 /* 75*39395Smckusick * 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; 89*39395Smckusick struct vnode *nvp; 90*39395Smckusick union nhead *nh; 91*39395Smckusick 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) { 100*39395Smckusick if (mntp != NFSTOV(np)->v_mount || 101*39395Smckusick bcmp((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH)) 102*39395Smckusick continue; 103*39395Smckusick /* 104*39395Smckusick * Following is essentially an inline expanded 105*39395Smckusick * copy of ngrab(), expanded inline for speed, 106*39395Smckusick * and so that the test for a mounted on nfsnode 107*39395Smckusick * can be deferred until after we are sure that 108*39395Smckusick * the nfsnode isn't busy. 109*39395Smckusick */ 110*39395Smckusick if ((np->n_flag & NLOCKED) != 0) { 111*39395Smckusick np->n_flag |= NWANT; 112*39395Smckusick sleep((caddr_t)np, PINOD); 113*39395Smckusick goto loop; 114*39395Smckusick } 115*39395Smckusick vp = NFSTOV(np); 116*39395Smckusick if (vp->v_count == 0) /* nfsnode on free list */ 117*39395Smckusick vget(vp); 118*39395Smckusick else 11938425Smckusick VREF(vp); 120*39395Smckusick np->n_flag |= NLOCKED; 121*39395Smckusick *npp = np; 122*39395Smckusick return(0); 12338884Smacklem } 124*39395Smckusick if (error = getnewvnode(VT_NFS, mntp, &nfsv2_vnodeops, &nvp)) { 12538415Smckusick *npp = 0; 126*39395Smckusick return (error); 12738415Smckusick } 128*39395Smckusick vp = nvp; 129*39395Smckusick np = VTONFS(vp); 130*39395Smckusick 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 } 165*39395Smckusick if (vp->v_count == 0) /* ino on free list */ 166*39395Smckusick vget(vp); 167*39395Smckusick else 168*39395Smckusick 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 180*39395Smckusick if (vp == NULL || vp->v_count != 0) 181*39395Smckusick panic("nfs_inactive: NULL or active vp"); 182*39395Smckusick np = VTONFS(vp); 183*39395Smckusick nfs_lock(vp); 184*39395Smckusick sp = np->n_sillyrename; 185*39395Smckusick np->n_sillyrename = (struct sillyrename *)0; 186*39395Smckusick if (sp) { 18738415Smckusick /* 188*39395Smckusick * Remove the silly file that was rename'd earlier 18938415Smckusick */ 190*39395Smckusick ndp = &sp->s_namei; 191*39395Smckusick if (!nfs_nget(vp->v_mount, &sp->s_fh, &dnp)) { 192*39395Smckusick ndp->ni_dvp = NFSTOV(dnp); 193*39395Smckusick nfs_removeit(ndp); 194*39395Smckusick nfs_nput(ndp->ni_dvp); 19538415Smckusick } 196*39395Smckusick crfree(ndp->ni_cred); 197*39395Smckusick free((caddr_t)sp, M_TEMP); 198*39395Smckusick } 199*39395Smckusick nfs_unlock(vp); 200*39395Smckusick np->n_flag = 0; 201*39395Smckusick #ifdef notdef 202*39395Smckusick /* 203*39395Smckusick * Scan the request list for any requests left hanging about 204*39395Smckusick */ 205*39395Smckusick s = splnet(); 206*39395Smckusick rep = nfsreqh.r_next; 207*39395Smckusick while (rep && rep != &nfsreqh) { 208*39395Smckusick if (rep->r_vp == vp) { 209*39395Smckusick rep->r_prev->r_next = rep2 = rep->r_next; 210*39395Smckusick rep->r_next->r_prev = rep->r_prev; 211*39395Smckusick m_freem(rep->r_mreq); 212*39395Smckusick if (rep->r_mrep != NULL) 213*39395Smckusick m_freem(rep->r_mrep); 214*39395Smckusick free((caddr_t)rep, M_NFSREQ); 215*39395Smckusick rep = rep2; 216*39395Smckusick } else 217*39395Smckusick rep = rep->r_next; 218*39395Smckusick } 219*39395Smckusick splx(s); 22038884Smacklem #endif 221*39395Smckusick return (0); 222*39395Smckusick } 223*39395Smckusick 224*39395Smckusick /* 225*39395Smckusick * Reclaim an nfsnode so that it can be used for other purposes. 226*39395Smckusick */ 227*39395Smckusick nfs_reclaim(vp) 228*39395Smckusick register struct vnode *vp; 229*39395Smckusick { 230*39395Smckusick register struct nfsnode *np = VTONFS(vp); 231*39395Smckusick 232*39395Smckusick if (vp->v_count != 0) 233*39395Smckusick panic("nfs_reclaim: active inode"); 234*39395Smckusick /* 235*39395Smckusick * Remove the nfsnode from its hash chain. 236*39395Smckusick */ 237*39395Smckusick remque(np); 238*39395Smckusick np->n_forw = np; 239*39395Smckusick np->n_back = np; 240*39395Smckusick cache_purge(vp); 241*39395Smckusick /* 242*39395Smckusick * Flush out any associated bio buffers that might be lying about 243*39395Smckusick * XXX n_flags are set to zero by nfs_inactive. 244*39395Smckusick */ 245*39395Smckusick if (vp->v_type == VREG && (np->n_flag & NBUFFERED)) { 246*39395Smckusick np->n_flag |= NLOCKED; 247*39395Smckusick nfs_blkflush(vp, (daddr_t)0, np->n_size, TRUE); 24838415Smckusick } 249*39395Smckusick vp->v_type = VNON; 25038415Smckusick return (0); 25138415Smckusick } 25238415Smckusick 25338415Smckusick /* 25438415Smckusick * Remove any nfsnodes in the nfsnode cache belonging to mount. 25538415Smckusick * 25638415Smckusick * There should not be any active ones, return error if any are found 25738415Smckusick * (nb: this is a user error, not a system err). 25838415Smckusick */ 25938415Smckusick nfs_nflush(mntp) 26038415Smckusick struct mount *mntp; 26138415Smckusick { 26238415Smckusick register struct vnode *vp; 263*39395Smckusick int busy = 0; 26438415Smckusick 265*39395Smckusick for (vp = mntp->m_mounth; vp; vp = vp->v_mountf) { 266*39395Smckusick if (vp->v_count) { 267*39395Smckusick busy++; 268*39395Smckusick continue; 269*39395Smckusick } 270*39395Smckusick /* 271*39395Smckusick * As v_count == 0, the nfsnode was on the free list already, 272*39395Smckusick * so it will fall off the bottom eventually. 273*39395Smckusick * We could perhaps move it to the head of the free list, 274*39395Smckusick * but as umounts are done so infrequently, we would gain 275*39395Smckusick * very little, while making the code bigger. 276*39395Smckusick */ 277*39395Smckusick nfs_reclaim(vp); 27838415Smckusick } 279*39395Smckusick if (busy) 280*39395Smckusick return (EBUSY); 28138415Smckusick return (0); 28238415Smckusick } 28338415Smckusick 28438415Smckusick /* 28538415Smckusick * Lock an nfsnode 28638415Smckusick */ 28738415Smckusick nfs_lock(vp) 28838415Smckusick struct vnode *vp; 28938415Smckusick { 29038415Smckusick register struct nfsnode *np = VTONFS(vp); 29138415Smckusick 29238415Smckusick while (np->n_flag & NLOCKED) { 29338415Smckusick np->n_flag |= NWANT; 29438415Smckusick sleep((caddr_t)np, PINOD); 29538415Smckusick } 29638415Smckusick np->n_flag |= NLOCKED; 29738415Smckusick } 29838415Smckusick 29938415Smckusick /* 30038415Smckusick * Unlock an nfsnode 30138415Smckusick */ 30238415Smckusick nfs_unlock(vp) 30338415Smckusick struct vnode *vp; 30438415Smckusick { 30538415Smckusick register struct nfsnode *np = VTONFS(vp); 30638415Smckusick 30738415Smckusick np->n_flag &= ~NLOCKED; 30838415Smckusick if (np->n_flag & NWANT) { 30938415Smckusick np->n_flag &= ~NWANT; 31038415Smckusick wakeup((caddr_t)np); 31138415Smckusick } 31238415Smckusick } 31338415Smckusick 31438415Smckusick /* 31538415Smckusick * Unlock and vrele() 31638415Smckusick * since I can't decide if dirs. should be locked, I will check for 31738415Smckusick * the lock and be flexible 31838415Smckusick */ 31938415Smckusick nfs_nput(vp) 32038415Smckusick struct vnode *vp; 32138415Smckusick { 32238415Smckusick register struct nfsnode *np = VTONFS(vp); 32338415Smckusick 32438415Smckusick if (np->n_flag & NLOCKED) 32538415Smckusick nfs_unlock(vp); 32638415Smckusick vrele(vp); 32738415Smckusick } 32838415Smckusick 32938415Smckusick nfs_abortop(ndp) 33038415Smckusick register struct nameidata *ndp; 33138415Smckusick { 33238415Smckusick register struct nfsnode *np; 33338415Smckusick 33438415Smckusick if (ndp->ni_vp != NULL) { 33538415Smckusick np = VTONFS(ndp->ni_vp); 33638415Smckusick if (np->n_flag & NLOCKED) 33738415Smckusick nfs_unlock(ndp->ni_vp); 33838415Smckusick vrele(ndp->ni_vp); 33938415Smckusick } 34038415Smckusick if (ndp->ni_dvp != NULL) { 34138415Smckusick np = VTONFS(ndp->ni_dvp); 34238415Smckusick if (np->n_flag & NLOCKED) 34338415Smckusick nfs_unlock(ndp->ni_dvp); 34438415Smckusick vrele(ndp->ni_dvp); 34538415Smckusick } 34638415Smckusick } 34738415Smckusick 34838415Smckusick /* 34938415Smckusick * This is silly, but if you use a macro and try and use it in a file 35038415Smckusick * that has mbuf.h included, m_data --> m_hdr.mh_data and this is not 35138415Smckusick * a good thing 35238415Smckusick */ 35338415Smckusick struct nfsmount *vfs_to_nfs(mp) 35438415Smckusick struct mount *mp; 35538415Smckusick { 35638415Smckusick return ((struct nfsmount *)mp->m_data); 35738415Smckusick } 358