1 /* 2 * Copyright (c) 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Rick Macklem at The University of Guelph. 7 * 8 * %sccs.include.redist.c% 9 * 10 * @(#)nfs_node.c 7.47 (Berkeley) 04/27/93 11 */ 12 13 #include <sys/param.h> 14 #include <sys/systm.h> 15 #include <sys/proc.h> 16 #include <sys/mount.h> 17 #include <sys/namei.h> 18 #include <sys/vnode.h> 19 #include <sys/kernel.h> 20 #include <sys/malloc.h> 21 22 #include <nfs/rpcv2.h> 23 #include <nfs/nfsv2.h> 24 #include <nfs/nfs.h> 25 #include <nfs/nfsnode.h> 26 #include <nfs/nfsmount.h> 27 #include <nfs/nqnfs.h> 28 29 struct nfsnode **nheadhashtbl; 30 u_long nheadhash; 31 #define NFSNOHASH(fhsum) ((fhsum)&nheadhash) 32 33 #define TRUE 1 34 #define FALSE 0 35 36 /* 37 * Initialize hash links for nfsnodes 38 * and build nfsnode free list. 39 */ 40 nfs_nhinit() 41 { 42 43 #ifndef lint 44 if ((sizeof(struct nfsnode) - 1) & sizeof(struct nfsnode)) 45 printf("nfs_nhinit: bad size %d\n", sizeof(struct nfsnode)); 46 #endif /* not lint */ 47 nheadhashtbl = hashinit(desiredvnodes, M_NFSNODE, &nheadhash); 48 } 49 50 /* 51 * Compute an entry in the NFS hash table structure 52 */ 53 struct nfsnode ** 54 nfs_hash(fhp) 55 register nfsv2fh_t *fhp; 56 { 57 register u_char *fhpp; 58 register u_long fhsum; 59 int i; 60 61 fhpp = &fhp->fh_bytes[0]; 62 fhsum = 0; 63 for (i = 0; i < NFSX_FH; i++) 64 fhsum += *fhpp++; 65 return (&nheadhashtbl[NFSNOHASH(fhsum)]); 66 } 67 68 /* 69 * Look up a vnode/nfsnode by file handle. 70 * Callers must check for mount points!! 71 * In all cases, a pointer to a 72 * nfsnode structure is returned. 73 */ 74 nfs_nget(mntp, fhp, npp) 75 struct mount *mntp; 76 register nfsv2fh_t *fhp; 77 struct nfsnode **npp; 78 { 79 register struct nfsnode *np, *nq, **nhpp; 80 register struct vnode *vp; 81 extern int (**nfsv2_vnodeop_p)(); 82 struct vnode *nvp; 83 int error; 84 85 nhpp = nfs_hash(fhp); 86 loop: 87 for (np = *nhpp; np; np = np->n_forw) { 88 if (mntp != NFSTOV(np)->v_mount || 89 bcmp((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH)) 90 continue; 91 vp = NFSTOV(np); 92 if (vget(vp)) 93 goto loop; 94 *npp = np; 95 return(0); 96 } 97 if (error = getnewvnode(VT_NFS, mntp, nfsv2_vnodeop_p, &nvp)) { 98 *npp = 0; 99 return (error); 100 } 101 vp = nvp; 102 MALLOC(np, struct nfsnode *, sizeof *np, M_NFSNODE, M_WAITOK); 103 vp->v_data = np; 104 np->n_vnode = vp; 105 /* 106 * Insert the nfsnode in the hash queue for its new file handle 107 */ 108 np->n_flag = 0; 109 if (nq = *nhpp) 110 nq->n_back = &np->n_forw; 111 np->n_forw = nq; 112 np->n_back = nhpp; 113 *nhpp = np; 114 bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH); 115 np->n_attrstamp = 0; 116 np->n_direofoffset = 0; 117 np->n_sillyrename = (struct sillyrename *)0; 118 np->n_size = 0; 119 np->n_mtime = 0; 120 if (VFSTONFS(mntp)->nm_flag & NFSMNT_NQNFS) { 121 np->n_brev = 0; 122 np->n_lrev = 0; 123 np->n_expiry = (time_t)0; 124 np->n_tnext = (struct nfsnode *)0; 125 } 126 *npp = np; 127 return (0); 128 } 129 130 nfs_inactive(ap) 131 struct vop_inactive_args /* { 132 struct vnode *a_vp; 133 } */ *ap; 134 { 135 register struct nfsnode *np; 136 register struct sillyrename *sp; 137 struct proc *p = curproc; /* XXX */ 138 extern int prtactive; 139 140 np = VTONFS(ap->a_vp); 141 if (prtactive && ap->a_vp->v_usecount != 0) 142 vprint("nfs_inactive: pushing active", ap->a_vp); 143 sp = np->n_sillyrename; 144 np->n_sillyrename = (struct sillyrename *)0; 145 if (sp) { 146 /* 147 * Remove the silly file that was rename'd earlier 148 */ 149 (void) nfs_vinvalbuf(ap->a_vp, 0, sp->s_cred, p, 1); 150 nfs_removeit(sp); 151 crfree(sp->s_cred); 152 vrele(sp->s_dvp); 153 #ifdef SILLYSEPARATE 154 free((caddr_t)sp, M_NFSREQ); 155 #endif 156 } 157 np->n_flag &= (NMODIFIED | NFLUSHINPROG | NFLUSHWANT | NQNFSEVICTED); 158 return (0); 159 } 160 161 /* 162 * Reclaim an nfsnode so that it can be used for other purposes. 163 */ 164 nfs_reclaim(ap) 165 struct vop_reclaim_args /* { 166 struct vnode *a_vp; 167 } */ *ap; 168 { 169 register struct vnode *vp = ap->a_vp; 170 register struct nfsnode *np = VTONFS(vp); 171 register struct nfsmount *nmp = VFSTONFS(vp->v_mount); 172 register struct nfsnode *nq; 173 extern int prtactive; 174 175 if (prtactive && vp->v_usecount != 0) 176 vprint("nfs_reclaim: pushing active", vp); 177 /* 178 * Remove the nfsnode from its hash chain. 179 */ 180 if (nq = np->n_forw) 181 nq->n_back = np->n_back; 182 *np->n_back = nq; 183 184 /* 185 * For nqnfs, take it off the timer queue as required. 186 */ 187 if ((nmp->nm_flag & NFSMNT_NQNFS) && np->n_tnext) { 188 if (np->n_tnext == (struct nfsnode *)nmp) 189 nmp->nm_tprev = np->n_tprev; 190 else 191 np->n_tnext->n_tprev = np->n_tprev; 192 if (np->n_tprev == (struct nfsnode *)nmp) 193 nmp->nm_tnext = np->n_tnext; 194 else 195 np->n_tprev->n_tnext = np->n_tnext; 196 } 197 cache_purge(vp); 198 FREE(vp->v_data, M_NFSNODE); 199 vp->v_data = (void *)0; 200 return (0); 201 } 202 203 /* 204 * Lock an nfsnode 205 */ 206 nfs_lock(ap) 207 struct vop_lock_args /* { 208 struct vnode *a_vp; 209 } */ *ap; 210 { 211 register struct vnode *vp = ap->a_vp; 212 213 /* 214 * Ugh, another place where interruptible mounts will get hung. 215 * If you make this sleep interruptible, then you have to fix all 216 * the VOP_LOCK() calls to expect interruptibility. 217 */ 218 while (vp->v_flag & VXLOCK) { 219 vp->v_flag |= VXWANT; 220 sleep((caddr_t)vp, PINOD); 221 } 222 if (vp->v_tag == VT_NON) 223 return (ENOENT); 224 return (0); 225 } 226 227 /* 228 * Unlock an nfsnode 229 */ 230 nfs_unlock(ap) 231 struct vop_unlock_args /* { 232 struct vnode *a_vp; 233 } */ *ap; 234 { 235 236 return (0); 237 } 238 239 /* 240 * Check for a locked nfsnode 241 */ 242 nfs_islocked(ap) 243 struct vop_islocked_args /* { 244 struct vnode *a_vp; 245 } */ *ap; 246 { 247 248 return (0); 249 } 250 251 /* 252 * Nfs abort op, called after namei() when a CREATE/DELETE isn't actually 253 * done. Currently nothing to do. 254 */ 255 /* ARGSUSED */ 256 int 257 nfs_abortop(ap) 258 struct vop_abortop_args /* { 259 struct vnode *a_dvp; 260 struct componentname *a_cnp; 261 } */ *ap; 262 { 263 264 if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) 265 FREE(ap->a_cnp->cn_pnbuf, M_NAMEI); 266 return (0); 267 } 268