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 spinlock_t vnumber_lock = SPIN_LOCK_UNLOCKED;
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
47 /*
48 * Translate stat(2) file types to vnode types and vice versa.
49 * Aware of numeric order of S_IFMT and vnode type values.
50 */
51 enum vtype iftovt_tab[] = {
52 VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON,
53 VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VNON
54 };
55
56 u_short vttoif_tab[] = {
57 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFIFO, 0, S_IFSOCK
58 };
59
60
61 void
vn_init(void)62 vn_init(void)
63 {
64 register sv_t *svp;
65 register int i;
66
67 for (svp = vsync, i = 0; i < NVSYNC; i++, svp++)
68 init_sv(svp, SV_DEFAULT, "vsy", i);
69 }
70
71 /*
72 * Clean a vnode of filesystem-specific data and prepare it for reuse.
73 */
74 STATIC int
vn_reclaim(struct vnode * vp)75 vn_reclaim(
76 struct vnode *vp)
77 {
78 int error;
79
80 XFS_STATS_INC(vn_reclaim);
81 vn_trace_entry(vp, "vn_reclaim", (inst_t *)__return_address);
82
83 /*
84 * Only make the VOP_RECLAIM call if there are behaviors
85 * to call.
86 */
87 if (vp->v_fbhv) {
88 VOP_RECLAIM(vp, error);
89 if (error)
90 return -error;
91 }
92 ASSERT(vp->v_fbhv == NULL);
93
94 VN_LOCK(vp);
95 vp->v_flag &= (VRECLM|VWAIT);
96 VN_UNLOCK(vp, 0);
97
98 vp->v_type = VNON;
99 vp->v_fbhv = NULL;
100
101 #ifdef XFS_VNODE_TRACE
102 ktrace_free(vp->v_trace);
103 vp->v_trace = NULL;
104 #endif
105
106 return 0;
107 }
108
109 STATIC void
vn_wakeup(struct vnode * vp)110 vn_wakeup(
111 struct vnode *vp)
112 {
113 VN_LOCK(vp);
114 if (vp->v_flag & VWAIT)
115 sv_broadcast(vptosync(vp));
116 vp->v_flag &= ~(VRECLM|VWAIT|VMODIFIED);
117 VN_UNLOCK(vp, 0);
118 }
119
120 int
vn_wait(struct vnode * vp)121 vn_wait(
122 struct vnode *vp)
123 {
124 VN_LOCK(vp);
125 if (vp->v_flag & (VINACT | VRECLM)) {
126 vp->v_flag |= VWAIT;
127 sv_wait(vptosync(vp), PINOD, &vp->v_lock, 0);
128 return 1;
129 }
130 VN_UNLOCK(vp, 0);
131 return 0;
132 }
133
134 struct vnode *
vn_initialize(struct inode * inode)135 vn_initialize(
136 struct inode *inode)
137 {
138 struct vnode *vp = LINVFS_GET_VP(inode);
139
140 XFS_STATS_INC(vn_active);
141 XFS_STATS_INC(vn_alloc);
142
143 vp->v_flag = VMODIFIED;
144 spinlock_init(&vp->v_lock, "v_lock");
145
146 spin_lock(&vnumber_lock);
147 if (!++vn_generation) /* v_number shouldn't be zero */
148 vn_generation++;
149 vp->v_number = vn_generation;
150 spin_unlock(&vnumber_lock);
151
152 ASSERT(VN_CACHED(vp) == 0);
153
154 /* Initialize the first behavior and the behavior chain head. */
155 vn_bhv_head_init(VN_BHV_HEAD(vp), "vnode");
156
157 #ifdef XFS_VNODE_TRACE
158 vp->v_trace = ktrace_alloc(VNODE_TRACE_SIZE, KM_SLEEP);
159 printk("Allocated VNODE_TRACE at 0x%p\n", vp->v_trace);
160 #endif /* XFS_VNODE_TRACE */
161
162 vn_trace_exit(vp, "vn_initialize", (inst_t *)__return_address);
163 return vp;
164 }
165
166 /*
167 * Get a reference on a vnode.
168 */
169 vnode_t *
vn_get(struct vnode * vp,vmap_t * vmap)170 vn_get(
171 struct vnode *vp,
172 vmap_t *vmap)
173 {
174 struct inode *inode;
175
176 XFS_STATS_INC(vn_get);
177 inode = LINVFS_GET_IP(vp);
178 if (inode->i_state & I_FREEING)
179 return NULL;
180
181 inode = VFS_GET_INODE(vmap->v_vfsp, vmap->v_ino, IGET_NOALLOC);
182 if (!inode) /* Inode not present */
183 return NULL;
184
185 /* We do not want to create new inodes via vn_get,
186 * returning NULL here is OK.
187 */
188 if (inode->i_state & I_NEW) {
189 vn_mark_bad(vp);
190 unlock_new_inode(inode);
191 iput(inode);
192 return NULL;
193 }
194
195 vn_trace_exit(vp, "vn_get", (inst_t *)__return_address);
196
197 return vp;
198 }
199
200 /*
201 * Revalidate the Linux inode from the vattr.
202 * Note: i_size _not_ updated; we must hold the inode
203 * semaphore when doing that - callers responsibility.
204 */
205 void
vn_revalidate_core(struct vnode * vp,vattr_t * vap)206 vn_revalidate_core(
207 struct vnode *vp,
208 vattr_t *vap)
209 {
210 struct inode *inode = LINVFS_GET_IP(vp);
211
212 inode->i_mode = VTTOIF(vap->va_type) | vap->va_mode;
213 inode->i_nlink = vap->va_nlink;
214 inode->i_uid = vap->va_uid;
215 inode->i_gid = vap->va_gid;
216 inode->i_blocks = vap->va_nblocks;
217 inode->i_mtime = vap->va_mtime.tv_sec;
218 inode->i_ctime = vap->va_ctime.tv_sec;
219 inode->i_atime = vap->va_atime.tv_sec;
220 if (vap->va_xflags & XFS_XFLAG_IMMUTABLE)
221 inode->i_flags |= S_IMMUTABLE;
222 else
223 inode->i_flags &= ~S_IMMUTABLE;
224 if (vap->va_xflags & XFS_XFLAG_APPEND)
225 inode->i_flags |= S_APPEND;
226 else
227 inode->i_flags &= ~S_APPEND;
228 if (vap->va_xflags & XFS_XFLAG_SYNC)
229 inode->i_flags |= S_SYNC;
230 else
231 inode->i_flags &= ~S_SYNC;
232 if (vap->va_xflags & XFS_XFLAG_NOATIME)
233 inode->i_flags |= S_NOATIME;
234 else
235 inode->i_flags &= ~S_NOATIME;
236 }
237
238 /*
239 * Revalidate the Linux inode from the vnode.
240 */
241 int
vn_revalidate(struct vnode * vp)242 vn_revalidate(
243 struct vnode *vp)
244 {
245 vattr_t va;
246 int error;
247
248 vn_trace_entry(vp, "vn_revalidate", (inst_t *)__return_address);
249 ASSERT(vp->v_fbhv != NULL);
250
251 va.va_mask = XFS_AT_STAT|XFS_AT_XFLAGS;
252 VOP_GETATTR(vp, &va, 0, NULL, error);
253 if (!error) {
254 vn_revalidate_core(vp, &va);
255 VUNMODIFY(vp);
256 }
257 return -error;
258 }
259
260 /*
261 * purge a vnode from the cache
262 * At this point the vnode is guaranteed to have no references (vn_count == 0)
263 * The caller has to make sure that there are no ways someone could
264 * get a handle (via vn_get) on the vnode (usually done via a mount/vfs lock).
265 */
266 void
vn_purge(struct vnode * vp,vmap_t * vmap)267 vn_purge(
268 struct vnode *vp,
269 vmap_t *vmap)
270 {
271 vn_trace_entry(vp, "vn_purge", (inst_t *)__return_address);
272
273 again:
274 /*
275 * Check whether vp has already been reclaimed since our caller
276 * sampled its version while holding a filesystem cache lock that
277 * its VOP_RECLAIM function acquires.
278 */
279 VN_LOCK(vp);
280 if (vp->v_number != vmap->v_number) {
281 VN_UNLOCK(vp, 0);
282 return;
283 }
284
285 /*
286 * If vp is being reclaimed or inactivated, wait until it is inert,
287 * then proceed. Can't assume that vnode is actually reclaimed
288 * just because the reclaimed flag is asserted -- a vn_alloc
289 * reclaim can fail.
290 */
291 if (vp->v_flag & (VINACT | VRECLM)) {
292 ASSERT(vn_count(vp) == 0);
293 vp->v_flag |= VWAIT;
294 sv_wait(vptosync(vp), PINOD, &vp->v_lock, 0);
295 goto again;
296 }
297
298 /*
299 * Another process could have raced in and gotten this vnode...
300 */
301 if (vn_count(vp) > 0) {
302 VN_UNLOCK(vp, 0);
303 return;
304 }
305
306 XFS_STATS_DEC(vn_active);
307 vp->v_flag |= VRECLM;
308 VN_UNLOCK(vp, 0);
309
310 /*
311 * Call VOP_RECLAIM and clean vp. The FSYNC_INVAL flag tells
312 * vp's filesystem to flush and invalidate all cached resources.
313 * When vn_reclaim returns, vp should have no private data,
314 * either in a system cache or attached to v_data.
315 */
316 if (vn_reclaim(vp) != 0)
317 panic("vn_purge: cannot reclaim");
318
319 /*
320 * Wakeup anyone waiting for vp to be reclaimed.
321 */
322 vn_wakeup(vp);
323 }
324
325 /*
326 * Add a reference to a referenced vnode.
327 */
328 struct vnode *
vn_hold(struct vnode * vp)329 vn_hold(
330 struct vnode *vp)
331 {
332 struct inode *inode;
333
334 XFS_STATS_INC(vn_hold);
335
336 VN_LOCK(vp);
337 inode = igrab(LINVFS_GET_IP(vp));
338 ASSERT(inode);
339 VN_UNLOCK(vp, 0);
340
341 return vp;
342 }
343
344 /*
345 * Call VOP_INACTIVE on last reference.
346 */
347 void
vn_rele(struct vnode * vp)348 vn_rele(
349 struct vnode *vp)
350 {
351 int vcnt;
352 int cache;
353
354 XFS_STATS_INC(vn_rele);
355
356 VN_LOCK(vp);
357
358 vn_trace_entry(vp, "vn_rele", (inst_t *)__return_address);
359 vcnt = vn_count(vp);
360
361 /*
362 * Since we always get called from put_inode we know
363 * that i_count won't be decremented after we
364 * return.
365 */
366 if (!vcnt) {
367 /*
368 * As soon as we turn this on, noone can find us in vn_get
369 * until we turn off VINACT or VRECLM
370 */
371 vp->v_flag |= VINACT;
372 VN_UNLOCK(vp, 0);
373
374 /*
375 * Do not make the VOP_INACTIVE call if there
376 * are no behaviors attached to the vnode to call.
377 */
378 if (vp->v_fbhv)
379 VOP_INACTIVE(vp, NULL, cache);
380
381 VN_LOCK(vp);
382 if (vp->v_flag & VWAIT)
383 sv_broadcast(vptosync(vp));
384
385 vp->v_flag &= ~(VINACT|VWAIT|VRECLM|VMODIFIED);
386 }
387
388 VN_UNLOCK(vp, 0);
389
390 vn_trace_exit(vp, "vn_rele", (inst_t *)__return_address);
391 }
392
393 /*
394 * Finish the removal of a vnode.
395 */
396 void
vn_remove(struct vnode * vp)397 vn_remove(
398 struct vnode *vp)
399 {
400 vmap_t vmap;
401
402 /* Make sure we don't do this to the same vnode twice */
403 if (!(vp->v_fbhv))
404 return;
405
406 XFS_STATS_INC(vn_remove);
407 vn_trace_exit(vp, "vn_remove", (inst_t *)__return_address);
408
409 /*
410 * After the following purge the vnode
411 * will no longer exist.
412 */
413 VMAP(vp, vmap);
414 vn_purge(vp, &vmap);
415 }
416
417
418 #ifdef XFS_VNODE_TRACE
419
420 #define KTRACE_ENTER(vp, vk, s, line, ra) \
421 ktrace_enter( (vp)->v_trace, \
422 /* 0 */ (void *)(__psint_t)(vk), \
423 /* 1 */ (void *)(s), \
424 /* 2 */ (void *)(__psint_t) line, \
425 /* 3 */ (void *)(vn_count(vp)), \
426 /* 4 */ (void *)(ra), \
427 /* 5 */ (void *)(__psunsigned_t)(vp)->v_flag, \
428 /* 6 */ (void *)(__psint_t)smp_processor_id(), \
429 /* 7 */ (void *)(__psint_t)(current->pid), \
430 /* 8 */ (void *)__return_address, \
431 /* 9 */ 0, 0, 0, 0, 0, 0, 0)
432
433 /*
434 * Vnode tracing code.
435 */
436 void
vn_trace_entry(vnode_t * vp,char * func,inst_t * ra)437 vn_trace_entry(vnode_t *vp, char *func, inst_t *ra)
438 {
439 KTRACE_ENTER(vp, VNODE_KTRACE_ENTRY, func, 0, ra);
440 }
441
442 void
vn_trace_exit(vnode_t * vp,char * func,inst_t * ra)443 vn_trace_exit(vnode_t *vp, char *func, inst_t *ra)
444 {
445 KTRACE_ENTER(vp, VNODE_KTRACE_EXIT, func, 0, ra);
446 }
447
448 void
vn_trace_hold(vnode_t * vp,char * file,int line,inst_t * ra)449 vn_trace_hold(vnode_t *vp, char *file, int line, inst_t *ra)
450 {
451 KTRACE_ENTER(vp, VNODE_KTRACE_HOLD, file, line, ra);
452 }
453
454 void
vn_trace_ref(vnode_t * vp,char * file,int line,inst_t * ra)455 vn_trace_ref(vnode_t *vp, char *file, int line, inst_t *ra)
456 {
457 KTRACE_ENTER(vp, VNODE_KTRACE_REF, file, line, ra);
458 }
459
460 void
vn_trace_rele(vnode_t * vp,char * file,int line,inst_t * ra)461 vn_trace_rele(vnode_t *vp, char *file, int line, inst_t *ra)
462 {
463 KTRACE_ENTER(vp, VNODE_KTRACE_RELE, file, line, ra);
464 }
465 #endif /* XFS_VNODE_TRACE */
466