Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify it | |
5 | * under the terms of version 2 of the GNU General Public License as | |
6 | * published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope that it would be useful, but | |
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
11 | * | |
12 | * Further, this software is distributed without any warranty that it is | |
13 | * free of the rightful claim of any third person regarding infringement | |
14 | * or the like. Any license provided herein, whether implied or | |
15 | * otherwise, applies only to this software file. Patent licenses, if | |
16 | * any, provided herein do not apply to combinations of this program with | |
17 | * other software, or any other product whatsoever. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License along | |
20 | * with this program; if not, write the Free Software Foundation, Inc., 59 | |
21 | * Temple Place - Suite 330, Boston MA 02111-1307, USA. | |
22 | * | |
23 | * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, | |
24 | * Mountain View, CA 94043, or: | |
25 | * | |
26 | * http://www.sgi.com | |
27 | * | |
28 | * For further information regarding this notice, see: | |
29 | * | |
30 | * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ | |
31 | */ | |
32 | ||
33 | #include "xfs.h" | |
34 | ||
35 | ||
36 | uint64_t vn_generation; /* vnode generation number */ | |
37 | DEFINE_SPINLOCK(vnumber_lock); | |
38 | ||
39 | /* | |
40 | * Dedicated vnode inactive/reclaim sync semaphores. | |
41 | * Prime number of hash buckets since address is used as the key. | |
42 | */ | |
43 | #define NVSYNC 37 | |
44 | #define vptosync(v) (&vsync[((unsigned long)v) % NVSYNC]) | |
45 | sv_t vsync[NVSYNC]; | |
46 | ||
1da177e4 LT |
47 | |
48 | void | |
49 | vn_init(void) | |
50 | { | |
51 | register sv_t *svp; | |
52 | register int i; | |
53 | ||
54 | for (svp = vsync, i = 0; i < NVSYNC; i++, svp++) | |
55 | init_sv(svp, SV_DEFAULT, "vsy", i); | |
56 | } | |
57 | ||
58 | /* | |
59 | * Clean a vnode of filesystem-specific data and prepare it for reuse. | |
60 | */ | |
61 | STATIC int | |
62 | vn_reclaim( | |
63 | struct vnode *vp) | |
64 | { | |
65 | int error; | |
66 | ||
67 | XFS_STATS_INC(vn_reclaim); | |
68 | vn_trace_entry(vp, "vn_reclaim", (inst_t *)__return_address); | |
69 | ||
70 | /* | |
71 | * Only make the VOP_RECLAIM call if there are behaviors | |
72 | * to call. | |
73 | */ | |
74 | if (vp->v_fbhv) { | |
75 | VOP_RECLAIM(vp, error); | |
76 | if (error) | |
77 | return -error; | |
78 | } | |
79 | ASSERT(vp->v_fbhv == NULL); | |
80 | ||
1da177e4 LT |
81 | vp->v_fbhv = NULL; |
82 | ||
83 | #ifdef XFS_VNODE_TRACE | |
84 | ktrace_free(vp->v_trace); | |
85 | vp->v_trace = NULL; | |
86 | #endif | |
87 | ||
88 | return 0; | |
89 | } | |
90 | ||
1da177e4 LT |
91 | struct vnode * |
92 | vn_initialize( | |
93 | struct inode *inode) | |
94 | { | |
95 | struct vnode *vp = LINVFS_GET_VP(inode); | |
96 | ||
97 | XFS_STATS_INC(vn_active); | |
98 | XFS_STATS_INC(vn_alloc); | |
99 | ||
100 | vp->v_flag = VMODIFIED; | |
101 | spinlock_init(&vp->v_lock, "v_lock"); | |
102 | ||
103 | spin_lock(&vnumber_lock); | |
104 | if (!++vn_generation) /* v_number shouldn't be zero */ | |
105 | vn_generation++; | |
106 | vp->v_number = vn_generation; | |
107 | spin_unlock(&vnumber_lock); | |
108 | ||
109 | ASSERT(VN_CACHED(vp) == 0); | |
110 | ||
111 | /* Initialize the first behavior and the behavior chain head. */ | |
112 | vn_bhv_head_init(VN_BHV_HEAD(vp), "vnode"); | |
113 | ||
114 | #ifdef XFS_VNODE_TRACE | |
115 | vp->v_trace = ktrace_alloc(VNODE_TRACE_SIZE, KM_SLEEP); | |
1da177e4 LT |
116 | #endif /* XFS_VNODE_TRACE */ |
117 | ||
118 | vn_trace_exit(vp, "vn_initialize", (inst_t *)__return_address); | |
119 | return vp; | |
120 | } | |
121 | ||
1da177e4 LT |
122 | /* |
123 | * Revalidate the Linux inode from the vattr. | |
124 | * Note: i_size _not_ updated; we must hold the inode | |
125 | * semaphore when doing that - callers responsibility. | |
126 | */ | |
127 | void | |
128 | vn_revalidate_core( | |
129 | struct vnode *vp, | |
130 | vattr_t *vap) | |
131 | { | |
132 | struct inode *inode = LINVFS_GET_IP(vp); | |
133 | ||
0432dab2 | 134 | inode->i_mode = vap->va_mode; |
1da177e4 LT |
135 | inode->i_nlink = vap->va_nlink; |
136 | inode->i_uid = vap->va_uid; | |
137 | inode->i_gid = vap->va_gid; | |
138 | inode->i_blocks = vap->va_nblocks; | |
139 | inode->i_mtime = vap->va_mtime; | |
140 | inode->i_ctime = vap->va_ctime; | |
141 | inode->i_atime = vap->va_atime; | |
142 | if (vap->va_xflags & XFS_XFLAG_IMMUTABLE) | |
143 | inode->i_flags |= S_IMMUTABLE; | |
144 | else | |
145 | inode->i_flags &= ~S_IMMUTABLE; | |
146 | if (vap->va_xflags & XFS_XFLAG_APPEND) | |
147 | inode->i_flags |= S_APPEND; | |
148 | else | |
149 | inode->i_flags &= ~S_APPEND; | |
150 | if (vap->va_xflags & XFS_XFLAG_SYNC) | |
151 | inode->i_flags |= S_SYNC; | |
152 | else | |
153 | inode->i_flags &= ~S_SYNC; | |
154 | if (vap->va_xflags & XFS_XFLAG_NOATIME) | |
155 | inode->i_flags |= S_NOATIME; | |
156 | else | |
157 | inode->i_flags &= ~S_NOATIME; | |
158 | } | |
159 | ||
160 | /* | |
161 | * Revalidate the Linux inode from the vnode. | |
162 | */ | |
163 | int | |
164 | vn_revalidate( | |
165 | struct vnode *vp) | |
166 | { | |
167 | vattr_t va; | |
168 | int error; | |
169 | ||
170 | vn_trace_entry(vp, "vn_revalidate", (inst_t *)__return_address); | |
171 | ASSERT(vp->v_fbhv != NULL); | |
172 | ||
173 | va.va_mask = XFS_AT_STAT|XFS_AT_XFLAGS; | |
174 | VOP_GETATTR(vp, &va, 0, NULL, error); | |
175 | if (!error) { | |
176 | vn_revalidate_core(vp, &va); | |
177 | VUNMODIFY(vp); | |
178 | } | |
179 | return -error; | |
180 | } | |
181 | ||
182 | /* | |
183 | * purge a vnode from the cache | |
184 | * At this point the vnode is guaranteed to have no references (vn_count == 0) | |
185 | * The caller has to make sure that there are no ways someone could | |
186 | * get a handle (via vn_get) on the vnode (usually done via a mount/vfs lock). | |
187 | */ | |
188 | void | |
189 | vn_purge( | |
190 | struct vnode *vp, | |
191 | vmap_t *vmap) | |
192 | { | |
193 | vn_trace_entry(vp, "vn_purge", (inst_t *)__return_address); | |
194 | ||
1da177e4 LT |
195 | /* |
196 | * Check whether vp has already been reclaimed since our caller | |
197 | * sampled its version while holding a filesystem cache lock that | |
198 | * its VOP_RECLAIM function acquires. | |
199 | */ | |
200 | VN_LOCK(vp); | |
201 | if (vp->v_number != vmap->v_number) { | |
202 | VN_UNLOCK(vp, 0); | |
203 | return; | |
204 | } | |
205 | ||
1da177e4 LT |
206 | /* |
207 | * Another process could have raced in and gotten this vnode... | |
208 | */ | |
209 | if (vn_count(vp) > 0) { | |
210 | VN_UNLOCK(vp, 0); | |
211 | return; | |
212 | } | |
213 | ||
214 | XFS_STATS_DEC(vn_active); | |
1da177e4 LT |
215 | VN_UNLOCK(vp, 0); |
216 | ||
217 | /* | |
218 | * Call VOP_RECLAIM and clean vp. The FSYNC_INVAL flag tells | |
219 | * vp's filesystem to flush and invalidate all cached resources. | |
220 | * When vn_reclaim returns, vp should have no private data, | |
221 | * either in a system cache or attached to v_data. | |
222 | */ | |
223 | if (vn_reclaim(vp) != 0) | |
224 | panic("vn_purge: cannot reclaim"); | |
1da177e4 LT |
225 | } |
226 | ||
227 | /* | |
228 | * Add a reference to a referenced vnode. | |
229 | */ | |
230 | struct vnode * | |
231 | vn_hold( | |
232 | struct vnode *vp) | |
233 | { | |
234 | struct inode *inode; | |
235 | ||
236 | XFS_STATS_INC(vn_hold); | |
237 | ||
238 | VN_LOCK(vp); | |
239 | inode = igrab(LINVFS_GET_IP(vp)); | |
240 | ASSERT(inode); | |
241 | VN_UNLOCK(vp, 0); | |
242 | ||
243 | return vp; | |
244 | } | |
245 | ||
246 | /* | |
247 | * Call VOP_INACTIVE on last reference. | |
248 | */ | |
249 | void | |
250 | vn_rele( | |
251 | struct vnode *vp) | |
252 | { | |
253 | int vcnt; | |
254 | int cache; | |
255 | ||
256 | XFS_STATS_INC(vn_rele); | |
257 | ||
258 | VN_LOCK(vp); | |
259 | ||
260 | vn_trace_entry(vp, "vn_rele", (inst_t *)__return_address); | |
261 | vcnt = vn_count(vp); | |
262 | ||
263 | /* | |
264 | * Since we always get called from put_inode we know | |
265 | * that i_count won't be decremented after we | |
266 | * return. | |
267 | */ | |
268 | if (!vcnt) { | |
1da177e4 LT |
269 | VN_UNLOCK(vp, 0); |
270 | ||
271 | /* | |
272 | * Do not make the VOP_INACTIVE call if there | |
273 | * are no behaviors attached to the vnode to call. | |
274 | */ | |
275 | if (vp->v_fbhv) | |
276 | VOP_INACTIVE(vp, NULL, cache); | |
277 | ||
278 | VN_LOCK(vp); | |
592cb26b | 279 | vp->v_flag &= ~VMODIFIED; |
1da177e4 LT |
280 | } |
281 | ||
282 | VN_UNLOCK(vp, 0); | |
283 | ||
284 | vn_trace_exit(vp, "vn_rele", (inst_t *)__return_address); | |
285 | } | |
286 | ||
287 | /* | |
288 | * Finish the removal of a vnode. | |
289 | */ | |
290 | void | |
291 | vn_remove( | |
292 | struct vnode *vp) | |
293 | { | |
294 | vmap_t vmap; | |
295 | ||
296 | /* Make sure we don't do this to the same vnode twice */ | |
297 | if (!(vp->v_fbhv)) | |
298 | return; | |
299 | ||
300 | XFS_STATS_INC(vn_remove); | |
301 | vn_trace_exit(vp, "vn_remove", (inst_t *)__return_address); | |
302 | ||
303 | /* | |
304 | * After the following purge the vnode | |
305 | * will no longer exist. | |
306 | */ | |
307 | VMAP(vp, vmap); | |
308 | vn_purge(vp, &vmap); | |
309 | } | |
310 | ||
311 | ||
312 | #ifdef XFS_VNODE_TRACE | |
313 | ||
314 | #define KTRACE_ENTER(vp, vk, s, line, ra) \ | |
315 | ktrace_enter( (vp)->v_trace, \ | |
316 | /* 0 */ (void *)(__psint_t)(vk), \ | |
317 | /* 1 */ (void *)(s), \ | |
318 | /* 2 */ (void *)(__psint_t) line, \ | |
02de1f0a | 319 | /* 3 */ (void *)(__psint_t)(vn_count(vp)), \ |
1da177e4 LT |
320 | /* 4 */ (void *)(ra), \ |
321 | /* 5 */ (void *)(__psunsigned_t)(vp)->v_flag, \ | |
322 | /* 6 */ (void *)(__psint_t)current_cpu(), \ | |
323 | /* 7 */ (void *)(__psint_t)current_pid(), \ | |
324 | /* 8 */ (void *)__return_address, \ | |
02de1f0a | 325 | /* 9 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL) |
1da177e4 LT |
326 | |
327 | /* | |
328 | * Vnode tracing code. | |
329 | */ | |
330 | void | |
764433b7 | 331 | vn_trace_entry(vnode_t *vp, const char *func, inst_t *ra) |
1da177e4 LT |
332 | { |
333 | KTRACE_ENTER(vp, VNODE_KTRACE_ENTRY, func, 0, ra); | |
334 | } | |
335 | ||
336 | void | |
764433b7 | 337 | vn_trace_exit(vnode_t *vp, const char *func, inst_t *ra) |
1da177e4 LT |
338 | { |
339 | KTRACE_ENTER(vp, VNODE_KTRACE_EXIT, func, 0, ra); | |
340 | } | |
341 | ||
342 | void | |
343 | vn_trace_hold(vnode_t *vp, char *file, int line, inst_t *ra) | |
344 | { | |
345 | KTRACE_ENTER(vp, VNODE_KTRACE_HOLD, file, line, ra); | |
346 | } | |
347 | ||
348 | void | |
349 | vn_trace_ref(vnode_t *vp, char *file, int line, inst_t *ra) | |
350 | { | |
351 | KTRACE_ENTER(vp, VNODE_KTRACE_REF, file, line, ra); | |
352 | } | |
353 | ||
354 | void | |
355 | vn_trace_rele(vnode_t *vp, char *file, int line, inst_t *ra) | |
356 | { | |
357 | KTRACE_ENTER(vp, VNODE_KTRACE_RELE, file, line, ra); | |
358 | } | |
359 | #endif /* XFS_VNODE_TRACE */ |