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.6 (Berkeley) 05/22/95
11 */
12
13
14 #include <sys/param.h>
15 #include <sys/systm.h>
16 #include <sys/proc.h>
17 #include <sys/mount.h>
18 #include <sys/namei.h>
19 #include <sys/vnode.h>
20 #include <sys/kernel.h>
21 #include <sys/malloc.h>
22
23 #include <nfs/rpcv2.h>
24 #include <nfs/nfsproto.h>
25 #include <nfs/nfs.h>
26 #include <nfs/nfsnode.h>
27 #include <nfs/nfsmount.h>
28 #include <nfs/nqnfs.h>
29
LIST_HEAD(nfsnodehashhead,nfsnode)30 LIST_HEAD(nfsnodehashhead, nfsnode) *nfsnodehashtbl;
31 u_long nfsnodehash;
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 void
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 u_long
nfs_hash(fhp,fhsize)55 nfs_hash(fhp, fhsize)
56 register nfsfh_t *fhp;
57 int fhsize;
58 {
59 register u_char *fhpp;
60 register u_long fhsum;
61 register int i;
62
63 fhpp = &fhp->fh_bytes[0];
64 fhsum = 0;
65 for (i = 0; i < fhsize; i++)
66 fhsum += *fhpp++;
67 return (fhsum);
68 }
69
70 /*
71 * Look up a vnode/nfsnode by file handle.
72 * Callers must check for mount points!!
73 * In all cases, a pointer to a
74 * nfsnode structure is returned.
75 */
76 int
nfs_nget(mntp,fhp,fhsize,npp)77 nfs_nget(mntp, fhp, fhsize, npp)
78 struct mount *mntp;
79 register nfsfh_t *fhp;
80 int fhsize;
81 struct nfsnode **npp;
82 {
83 struct proc *p = curproc; /* XXX */
84 struct nfsnode *np;
85 struct nfsnodehashhead *nhpp;
86 register struct vnode *vp;
87 extern int (**nfsv2_vnodeop_p)();
88 struct vnode *nvp;
89 int error;
90
91 nhpp = NFSNOHASH(nfs_hash(fhp, fhsize));
92 loop:
93 for (np = nhpp->lh_first; np != 0; np = np->n_hash.le_next) {
94 if (mntp != NFSTOV(np)->v_mount || np->n_fhsize != fhsize ||
95 bcmp((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize))
96 continue;
97 vp = NFSTOV(np);
98 if (vget(vp, LK_EXCLUSIVE, p))
99 goto loop;
100 *npp = np;
101 return(0);
102 }
103 error = getnewvnode(VT_NFS, mntp, nfsv2_vnodeop_p, &nvp);
104 if (error) {
105 *npp = 0;
106 return (error);
107 }
108 vp = nvp;
109 MALLOC(np, struct nfsnode *, sizeof *np, M_NFSNODE, M_WAITOK);
110 bzero((caddr_t)np, sizeof *np);
111 vp->v_data = np;
112 np->n_vnode = vp;
113 /*
114 * Insert the nfsnode in the hash queue for its new file handle
115 */
116 LIST_INSERT_HEAD(nhpp, np, n_hash);
117 if (fhsize > NFS_SMALLFH) {
118 MALLOC(np->n_fhp, nfsfh_t *, fhsize, M_NFSBIGFH, M_WAITOK);
119 } else
120 np->n_fhp = &np->n_fh;
121 bcopy((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize);
122 np->n_fhsize = fhsize;
123 *npp = np;
124 return (0);
125 }
126
127 int
nfs_inactive(ap)128 nfs_inactive(ap)
129 struct vop_inactive_args /* {
130 struct vnode *a_vp;
131 struct proc *a_p;
132 } */ *ap;
133 {
134 register struct nfsnode *np;
135 register struct sillyrename *sp;
136 struct proc *p = curproc; /* XXX */
137 extern int prtactive;
138
139 np = VTONFS(ap->a_vp);
140 if (prtactive && ap->a_vp->v_usecount != 0)
141 vprint("nfs_inactive: pushing active", ap->a_vp);
142 if (ap->a_vp->v_type != VDIR)
143 sp = np->n_sillyrename;
144 else
145 sp = (struct sillyrename *)0;
146 np->n_sillyrename = (struct sillyrename *)0;
147 if (sp) {
148 /*
149 * Remove the silly file that was rename'd earlier
150 */
151 (void) nfs_vinvalbuf(ap->a_vp, 0, sp->s_cred, p, 1);
152 nfs_removeit(sp);
153 crfree(sp->s_cred);
154 vrele(sp->s_dvp);
155 FREE((caddr_t)sp, M_NFSREQ);
156 }
157 np->n_flag &= (NMODIFIED | NFLUSHINPROG | NFLUSHWANT | NQNFSEVICTED |
158 NQNFSNONCACHE | NQNFSWRITE);
159 VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
160 return (0);
161 }
162
163 /*
164 * Reclaim an nfsnode so that it can be used for other purposes.
165 */
166 int
nfs_reclaim(ap)167 nfs_reclaim(ap)
168 struct vop_reclaim_args /* {
169 struct vnode *a_vp;
170 } */ *ap;
171 {
172 register struct vnode *vp = ap->a_vp;
173 register struct nfsnode *np = VTONFS(vp);
174 register struct nfsmount *nmp = VFSTONFS(vp->v_mount);
175 register struct nfsdmap *dp, *dp2;
176 extern int prtactive;
177
178 if (prtactive && vp->v_usecount != 0)
179 vprint("nfs_reclaim: pushing active", vp);
180
181 LIST_REMOVE(np, n_hash);
182
183 /*
184 * For nqnfs, take it off the timer queue as required.
185 */
186 if ((nmp->nm_flag & NFSMNT_NQNFS) && np->n_timer.cqe_next != 0) {
187 CIRCLEQ_REMOVE(&nmp->nm_timerhead, np, n_timer);
188 }
189
190 /*
191 * Free up any directory cookie structures and
192 * large file handle structures that might be associated with
193 * this nfs node.
194 */
195 if (vp->v_type == VDIR) {
196 dp = np->n_cookies.lh_first;
197 while (dp) {
198 dp2 = dp;
199 dp = dp->ndm_list.le_next;
200 FREE((caddr_t)dp2, M_NFSDIROFF);
201 }
202 }
203 if (np->n_fhsize > NFS_SMALLFH) {
204 FREE((caddr_t)np->n_fhp, M_NFSBIGFH);
205 }
206
207 cache_purge(vp);
208 FREE(vp->v_data, M_NFSNODE);
209 vp->v_data = (void *)0;
210 return (0);
211 }
212
213 /*
214 * Nfs abort op, called after namei() when a CREATE/DELETE isn't actually
215 * done. Currently nothing to do.
216 */
217 /* ARGSUSED */
218 int
nfs_abortop(ap)219 nfs_abortop(ap)
220 struct vop_abortop_args /* {
221 struct vnode *a_dvp;
222 struct componentname *a_cnp;
223 } */ *ap;
224 {
225
226 if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
227 FREE(ap->a_cnp->cn_pnbuf, M_NAMEI);
228 return (0);
229 }
230