1*38415Smckusick /* 2*38415Smckusick * Copyright (c) 1989 The Regents of the University of California. 3*38415Smckusick * All rights reserved. 4*38415Smckusick * 5*38415Smckusick * This code is derived from software contributed to Berkeley by 6*38415Smckusick * Rick Macklem at The University of Guelph. 7*38415Smckusick * 8*38415Smckusick * Redistribution and use in source and binary forms are permitted 9*38415Smckusick * provided that the above copyright notice and this paragraph are 10*38415Smckusick * duplicated in all such forms and that any documentation, 11*38415Smckusick * advertising materials, and other materials related to such 12*38415Smckusick * distribution and use acknowledge that the software was developed 13*38415Smckusick * by the University of California, Berkeley. The name of the 14*38415Smckusick * University may not be used to endorse or promote products derived 15*38415Smckusick * from this software without specific prior written permission. 16*38415Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17*38415Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18*38415Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19*38415Smckusick * 20*38415Smckusick * @(#)nfs_node.c 7.1 (Berkeley) 07/05/89 21*38415Smckusick */ 22*38415Smckusick 23*38415Smckusick #include "param.h" 24*38415Smckusick #include "systm.h" 25*38415Smckusick #include "user.h" 26*38415Smckusick #include "proc.h" 27*38415Smckusick #include "mount.h" 28*38415Smckusick #include "vnode.h" 29*38415Smckusick #include "dir.h" 30*38415Smckusick #include "namei.h" 31*38415Smckusick #include "errno.h" 32*38415Smckusick #include "nfsv2.h" 33*38415Smckusick #include "nfs.h" 34*38415Smckusick #include "nfsnode.h" 35*38415Smckusick #include "nfsmount.h" 36*38415Smckusick #include "kernel.h" 37*38415Smckusick #include "malloc.h" 38*38415Smckusick 39*38415Smckusick /* The request list head */ 40*38415Smckusick extern struct nfsreq nfsreqh; 41*38415Smckusick 42*38415Smckusick /* Someday this should be dynamically sized like the inode table */ 43*38415Smckusick struct nfsnode nfsnd[2000]; 44*38415Smckusick struct nfsnode *nfsnode = &nfsnd[0]; 45*38415Smckusick struct nfsnode *nfsnodeNNFSNODE = &nfsnd[2000]; 46*38415Smckusick int nnfsnode = 2000; 47*38415Smckusick 48*38415Smckusick #define NFSNOHSZ 512 49*38415Smckusick #if ((NFSNOHSZ&(NFSNOHSZ-1)) == 0) 50*38415Smckusick #define NFSNOHASH(fhsum) ((fhsum)&(NFSNOHSZ-1)) 51*38415Smckusick #else 52*38415Smckusick #define NFSNOHASH(fhsum) (((unsigned)(fhsum))%NFSNOHSZ) 53*38415Smckusick #endif 54*38415Smckusick 55*38415Smckusick union nhead { /* inode LRU cache, Chris Maltby */ 56*38415Smckusick union nhead *nh_head[2]; 57*38415Smckusick struct nfsnode *nh_chain[2]; 58*38415Smckusick } nhead[NFSNOHSZ]; 59*38415Smckusick 60*38415Smckusick struct nfsnode *nfreeh, **nfreet; 61*38415Smckusick 62*38415Smckusick /* 63*38415Smckusick * Initialize hash links for nfsnodes 64*38415Smckusick * and build nfsnode free list. 65*38415Smckusick */ 66*38415Smckusick nfs_nhinit() 67*38415Smckusick { 68*38415Smckusick register int i; 69*38415Smckusick register struct nfsnode *np = nfsnode; 70*38415Smckusick register union nhead *nh = nhead; 71*38415Smckusick 72*38415Smckusick for (i = NFSNOHSZ; --i >= 0; nh++) { 73*38415Smckusick nh->nh_head[0] = nh; 74*38415Smckusick nh->nh_head[1] = nh; 75*38415Smckusick } 76*38415Smckusick nfreeh = np; 77*38415Smckusick nfreet = &np->n_freef; 78*38415Smckusick np->n_freeb = &nfreeh; 79*38415Smckusick np->n_forw = np; 80*38415Smckusick np->n_back = np; 81*38415Smckusick NFSTOV(np)->v_data = (qaddr_t)np; 82*38415Smckusick for (i = nnfsnode; --i > 0; ) { 83*38415Smckusick ++np; 84*38415Smckusick np->n_forw = np; 85*38415Smckusick np->n_back = np; 86*38415Smckusick NFSTOV(np)->v_data = (qaddr_t)np; 87*38415Smckusick *nfreet = np; 88*38415Smckusick np->n_freeb = nfreet; 89*38415Smckusick nfreet = &np->n_freef; 90*38415Smckusick } 91*38415Smckusick np->n_freef = NULL; 92*38415Smckusick } 93*38415Smckusick 94*38415Smckusick /* 95*38415Smckusick * Look up an vnode/nfsnode by file handle. 96*38415Smckusick * Callers must check for mount points!! 97*38415Smckusick * In all cases, a pointer to a 98*38415Smckusick * nfsnode structure is returned. 99*38415Smckusick */ 100*38415Smckusick nfs_nget(mntp, fhp, npp) 101*38415Smckusick struct mount *mntp; 102*38415Smckusick register nfsv2fh_t *fhp; 103*38415Smckusick struct nfsnode **npp; 104*38415Smckusick { 105*38415Smckusick register struct nfsnode *np; 106*38415Smckusick register struct vnode *vp; 107*38415Smckusick register struct nfsnode *nq; 108*38415Smckusick register u_char *fhpp; 109*38415Smckusick register u_long fhsum; 110*38415Smckusick register int i; 111*38415Smckusick union nhead *nh; 112*38415Smckusick int error; 113*38415Smckusick 114*38415Smckusick fhpp = &fhp->fh_bytes[0]; 115*38415Smckusick fhsum = 0; 116*38415Smckusick for (i = 0; i < NFSX_FH; i++) 117*38415Smckusick fhsum += *fhpp++; 118*38415Smckusick loop: 119*38415Smckusick nh = &nhead[NFSNOHASH(fhsum)]; 120*38415Smckusick for (np = nh->nh_chain[0]; np != (struct nfsnode *)nh; np = np->n_forw) 121*38415Smckusick if (mntp == NFSTOV(np)->v_mount && 122*38415Smckusick !bcmp((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH)) { 123*38415Smckusick /* 124*38415Smckusick * Following is essentially an inline expanded 125*38415Smckusick * copy of ngrab(), expanded inline for speed, 126*38415Smckusick * and so that the test for a mounted on nfsnode 127*38415Smckusick * can be deferred until after we are sure that 128*38415Smckusick * the nfsnode isn't busy. 129*38415Smckusick */ 130*38415Smckusick if ((np->n_flag & NLOCKED) != 0) { 131*38415Smckusick np->n_flag |= NWANT; 132*38415Smckusick sleep((caddr_t)np, PINOD); 133*38415Smckusick goto loop; 134*38415Smckusick } 135*38415Smckusick vp = NFSTOV(np); 136*38415Smckusick if (vp->v_count == 0) { /* nfsno on free list */ 137*38415Smckusick if (nq = np->n_freef) 138*38415Smckusick nq->n_freeb = np->n_freeb; 139*38415Smckusick else 140*38415Smckusick nfreet = np->n_freeb; 141*38415Smckusick *np->n_freeb = nq; 142*38415Smckusick np->n_freef = NULL; 143*38415Smckusick np->n_freeb = NULL; 144*38415Smckusick } 145*38415Smckusick np->n_flag |= NLOCKED; 146*38415Smckusick vp->v_count++; 147*38415Smckusick *npp = np; 148*38415Smckusick return(0); 149*38415Smckusick } 150*38415Smckusick 151*38415Smckusick if ((np = nfreeh) == NULL) { 152*38415Smckusick tablefull("nfsnode"); 153*38415Smckusick *npp = 0; 154*38415Smckusick return(ENFILE); 155*38415Smckusick } 156*38415Smckusick vp = NFSTOV(np); 157*38415Smckusick if (vp->v_count) 158*38415Smckusick panic("free nfsnode isn't"); 159*38415Smckusick if (nq = np->n_freef) 160*38415Smckusick nq->n_freeb = &nfreeh; 161*38415Smckusick nfreeh = nq; 162*38415Smckusick np->n_freef = NULL; 163*38415Smckusick np->n_freeb = NULL; 164*38415Smckusick /* 165*38415Smckusick * Now to take nfsnode off the hash chain it was on 166*38415Smckusick * (initially, or after an nflush, it is on a "hash chain" 167*38415Smckusick * consisting entirely of itself, and pointed to by no-one, 168*38415Smckusick * but that doesn't matter), and put it on the chain for 169*38415Smckusick * its new file handle 170*38415Smckusick */ 171*38415Smckusick remque(np); 172*38415Smckusick insque(np, nh); 173*38415Smckusick bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH); 174*38415Smckusick #ifdef notyet 175*38415Smckusick cache_purge(vp); 176*38415Smckusick #endif 177*38415Smckusick np->n_flag = NLOCKED; 178*38415Smckusick np->n_attrstamp = 0; 179*38415Smckusick np->n_sillyrename = (struct sillyrename *)0; 180*38415Smckusick np->n_id = ++nextnfsnodeid; 181*38415Smckusick /* 182*38415Smckusick * Initialize the associated vnode 183*38415Smckusick */ 184*38415Smckusick vinit(vp, mntp, VNON, &nfsv2_vnodeops); 185*38415Smckusick *npp = np; 186*38415Smckusick return (0); 187*38415Smckusick } 188*38415Smckusick 189*38415Smckusick /* 190*38415Smckusick * Convert a pointer to an nfsnode into a reference to an nfsnode. 191*38415Smckusick * 192*38415Smckusick * This is basically the internal piece of nget (after the 193*38415Smckusick * nfsnode pointer is located) but without the test for mounted 194*38415Smckusick * filesystems. It is caller's responsibility to check that 195*38415Smckusick * the nfsnode pointer is valid. 196*38415Smckusick */ 197*38415Smckusick nfs_ngrab(np) 198*38415Smckusick register struct nfsnode *np; 199*38415Smckusick { 200*38415Smckusick register struct vnode *vp = NFSTOV(np); 201*38415Smckusick 202*38415Smckusick while ((np->n_flag & NLOCKED) != 0) { 203*38415Smckusick np->n_flag |= NWANT; 204*38415Smckusick sleep((caddr_t)np, PINOD); 205*38415Smckusick } 206*38415Smckusick if (vp->v_count == 0) { /* ino on free list */ 207*38415Smckusick register struct nfsnode *nq; 208*38415Smckusick 209*38415Smckusick if (nq = np->n_freef) 210*38415Smckusick nq->n_freeb = np->n_freeb; 211*38415Smckusick else 212*38415Smckusick nfreet = np->n_freeb; 213*38415Smckusick *np->n_freeb = nq; 214*38415Smckusick np->n_freef = NULL; 215*38415Smckusick np->n_freeb = NULL; 216*38415Smckusick } 217*38415Smckusick vp->v_count++; 218*38415Smckusick np->n_flag |= NLOCKED; 219*38415Smckusick } 220*38415Smckusick 221*38415Smckusick nfs_inactive(vp) 222*38415Smckusick struct vnode *vp; 223*38415Smckusick { 224*38415Smckusick register struct nfsnode *np; 225*38415Smckusick register struct nameidata *ndp; 226*38415Smckusick register struct sillyrename *sp; 227*38415Smckusick register struct nfsreq *rep; 228*38415Smckusick struct nfsreq *rep2; 229*38415Smckusick struct nfsnode *dnp; 230*38415Smckusick int s; 231*38415Smckusick 232*38415Smckusick if (vp == NULL) 233*38415Smckusick panic("nfs_inactive NULL vp"); 234*38415Smckusick if (vp->v_count == 0) { 235*38415Smckusick np = VTONFS(vp); 236*38415Smckusick np->n_flag |= NLOCKED; 237*38415Smckusick if (np->n_sillyrename) { 238*38415Smckusick /* 239*38415Smckusick * Remove the silly file that was rename'd earlier 240*38415Smckusick */ 241*38415Smckusick sp = np->n_sillyrename; 242*38415Smckusick ndp = &sp->s_namei; 243*38415Smckusick if (!nfs_nget(vp->v_mount, &sp->s_fh, &dnp)) { 244*38415Smckusick ndp->ni_dvp = NFSTOV(dnp); 245*38415Smckusick if (sp->s_flag == REMOVE) 246*38415Smckusick nfs_removeit(ndp); 247*38415Smckusick else 248*38415Smckusick nfs_rmdirit(ndp); 249*38415Smckusick nfs_nput(ndp->ni_dvp); 250*38415Smckusick } 251*38415Smckusick crfree(ndp->ni_cred); 252*38415Smckusick free((caddr_t)sp, M_TEMP); 253*38415Smckusick np->n_sillyrename = (struct sillyrename *)0; 254*38415Smckusick } 255*38415Smckusick nfs_unlock(vp); 256*38415Smckusick np->n_flag = 0; 257*38415Smckusick /* 258*38415Smckusick * Scan the request list for any requests left hanging about 259*38415Smckusick */ 260*38415Smckusick s = splnet(); 261*38415Smckusick rep = nfsreqh.r_next; 262*38415Smckusick while (rep) { 263*38415Smckusick if (rep->r_vp == vp) { 264*38415Smckusick rep->r_prev->r_next = rep2 = rep->r_next; 265*38415Smckusick if (rep->r_next != NULL) 266*38415Smckusick rep->r_next->r_prev = rep->r_prev; 267*38415Smckusick m_freem(rep->r_mreq); 268*38415Smckusick if (rep->r_mrep != NULL) 269*38415Smckusick m_freem(rep->r_mrep); 270*38415Smckusick free((caddr_t)rep, M_NFSREQ); 271*38415Smckusick rep = rep2; 272*38415Smckusick } else 273*38415Smckusick rep = rep->r_next; 274*38415Smckusick } 275*38415Smckusick splx(s); 276*38415Smckusick /* 277*38415Smckusick * Put the nfsnode on the end of the free list. 278*38415Smckusick */ 279*38415Smckusick if (nfreeh) { 280*38415Smckusick *nfreet = np; 281*38415Smckusick np->n_freeb = nfreet; 282*38415Smckusick } else { 283*38415Smckusick nfreeh = np; 284*38415Smckusick np->n_freeb = &nfreeh; 285*38415Smckusick } 286*38415Smckusick np->n_freef = NULL; 287*38415Smckusick nfreet = &np->n_freef; 288*38415Smckusick } 289*38415Smckusick return (0); 290*38415Smckusick } 291*38415Smckusick 292*38415Smckusick /* 293*38415Smckusick * Remove any nfsnodes in the nfsnode cache belonging to mount. 294*38415Smckusick * 295*38415Smckusick * There should not be any active ones, return error if any are found 296*38415Smckusick * (nb: this is a user error, not a system err). 297*38415Smckusick */ 298*38415Smckusick nfs_nflush(mntp) 299*38415Smckusick struct mount *mntp; 300*38415Smckusick { 301*38415Smckusick register struct nfsnode *np; 302*38415Smckusick register struct vnode *vp; 303*38415Smckusick 304*38415Smckusick for (np = nfsnode; np < nfsnodeNNFSNODE; np++) { 305*38415Smckusick vp = NFSTOV(np); 306*38415Smckusick if (vp->v_mount == mntp) 307*38415Smckusick if (vp->v_count) 308*38415Smckusick return (EBUSY); 309*38415Smckusick else { 310*38415Smckusick remque(np); 311*38415Smckusick np->n_forw = np; 312*38415Smckusick np->n_back = np; 313*38415Smckusick /* 314*38415Smckusick * as v_count == 0, the inode was on the free 315*38415Smckusick * list already, just leave it there, it will 316*38415Smckusick * fall off the bottom eventually. We could 317*38415Smckusick * perhaps move it to the head of the free 318*38415Smckusick * list, but as umounts are done so 319*38415Smckusick * infrequently, we would gain very little, 320*38415Smckusick * while making the code bigger. 321*38415Smckusick */ 322*38415Smckusick } 323*38415Smckusick } 324*38415Smckusick return (0); 325*38415Smckusick } 326*38415Smckusick 327*38415Smckusick /* 328*38415Smckusick * Lock an nfsnode 329*38415Smckusick */ 330*38415Smckusick nfs_lock(vp) 331*38415Smckusick struct vnode *vp; 332*38415Smckusick { 333*38415Smckusick register struct nfsnode *np = VTONFS(vp); 334*38415Smckusick 335*38415Smckusick if (np->n_flag & NLOCKED) 336*38415Smckusick printf("pid %d hit locked nfsnode=0x%x\n", 337*38415Smckusick u.u_procp->p_pid, np); 338*38415Smckusick while (np->n_flag & NLOCKED) { 339*38415Smckusick np->n_flag |= NWANT; 340*38415Smckusick sleep((caddr_t)np, PINOD); 341*38415Smckusick } 342*38415Smckusick np->n_flag |= NLOCKED; 343*38415Smckusick } 344*38415Smckusick 345*38415Smckusick /* 346*38415Smckusick * Unlock an nfsnode 347*38415Smckusick */ 348*38415Smckusick nfs_unlock(vp) 349*38415Smckusick struct vnode *vp; 350*38415Smckusick { 351*38415Smckusick register struct nfsnode *np = VTONFS(vp); 352*38415Smckusick 353*38415Smckusick if ((np->n_flag & NLOCKED) == 0) { 354*38415Smckusick printf("pid %d unlocking unlocked nfsnode=0x%x ", 355*38415Smckusick u.u_procp->p_pid, np); 356*38415Smckusick 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", 357*38415Smckusick np->n_fh.fh_bytes[0],np->n_fh.fh_bytes[1], 358*38415Smckusick np->n_fh.fh_bytes[2],np->n_fh.fh_bytes[3], 359*38415Smckusick np->n_fh.fh_bytes[4],np->n_fh.fh_bytes[5], 360*38415Smckusick np->n_fh.fh_bytes[6],np->n_fh.fh_bytes[7]); 361*38415Smckusick } 362*38415Smckusick np->n_flag &= ~NLOCKED; 363*38415Smckusick if (np->n_flag & NWANT) { 364*38415Smckusick np->n_flag &= ~NWANT; 365*38415Smckusick wakeup((caddr_t)np); 366*38415Smckusick } 367*38415Smckusick } 368*38415Smckusick 369*38415Smckusick /* 370*38415Smckusick * Unlock and vrele() 371*38415Smckusick * since I can't decide if dirs. should be locked, I will check for 372*38415Smckusick * the lock and be flexible 373*38415Smckusick */ 374*38415Smckusick nfs_nput(vp) 375*38415Smckusick struct vnode *vp; 376*38415Smckusick { 377*38415Smckusick register struct nfsnode *np = VTONFS(vp); 378*38415Smckusick 379*38415Smckusick if (np->n_flag & NLOCKED) 380*38415Smckusick nfs_unlock(vp); 381*38415Smckusick vrele(vp); 382*38415Smckusick } 383*38415Smckusick 384*38415Smckusick nfs_abortop(ndp) 385*38415Smckusick register struct nameidata *ndp; 386*38415Smckusick { 387*38415Smckusick register struct nfsnode *np; 388*38415Smckusick 389*38415Smckusick if (ndp->ni_vp != NULL) { 390*38415Smckusick np = VTONFS(ndp->ni_vp); 391*38415Smckusick if (np->n_flag & NLOCKED) 392*38415Smckusick nfs_unlock(ndp->ni_vp); 393*38415Smckusick vrele(ndp->ni_vp); 394*38415Smckusick } 395*38415Smckusick if (ndp->ni_dvp != NULL) { 396*38415Smckusick np = VTONFS(ndp->ni_dvp); 397*38415Smckusick if (np->n_flag & NLOCKED) 398*38415Smckusick nfs_unlock(ndp->ni_dvp); 399*38415Smckusick vrele(ndp->ni_dvp); 400*38415Smckusick } 401*38415Smckusick } 402*38415Smckusick 403*38415Smckusick /* 404*38415Smckusick * This is silly, but if you use a macro and try and use it in a file 405*38415Smckusick * that has mbuf.h included, m_data --> m_hdr.mh_data and this is not 406*38415Smckusick * a good thing 407*38415Smckusick */ 408*38415Smckusick struct nfsmount *vfs_to_nfs(mp) 409*38415Smckusick struct mount *mp; 410*38415Smckusick { 411*38415Smckusick return ((struct nfsmount *)mp->m_data); 412*38415Smckusick } 413