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