]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - fs/xfs/linux-2.6/xfs_vnode.c
9d9464cf8de4de637f785ce5776ef4bdcf8d52ae
[linux-2.6-omap-h63xx.git] / fs / xfs / linux-2.6 / xfs_vnode.c
1 /*
2  * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
3  * All Rights Reserved.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it would be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write the Free Software Foundation,
16  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18 #include "xfs.h"
19 #include "xfs_vnodeops.h"
20 #include "xfs_bmap_btree.h"
21 #include "xfs_inode.h"
22
23 /*
24  * And this gunk is needed for xfs_mount.h"
25  */
26 #include "xfs_log.h"
27 #include "xfs_trans.h"
28 #include "xfs_sb.h"
29 #include "xfs_dmapi.h"
30 #include "xfs_inum.h"
31 #include "xfs_ag.h"
32 #include "xfs_mount.h"
33
34 uint64_t vn_generation;         /* vnode generation number */
35 DEFINE_SPINLOCK(vnumber_lock);
36
37 /*
38  * Dedicated vnode inactive/reclaim sync semaphores.
39  * Prime number of hash buckets since address is used as the key.
40  */
41 #define NVSYNC                  37
42 #define vptosync(v)             (&vsync[((unsigned long)v) % NVSYNC])
43 static wait_queue_head_t vsync[NVSYNC];
44
45 void
46 vn_init(void)
47 {
48         int i;
49
50         for (i = 0; i < NVSYNC; i++)
51                 init_waitqueue_head(&vsync[i]);
52 }
53
54 void
55 vn_iowait(
56         xfs_inode_t     *ip)
57 {
58         wait_queue_head_t *wq = vptosync(ip);
59
60         wait_event(*wq, (atomic_read(&ip->i_iocount) == 0));
61 }
62
63 void
64 vn_iowake(
65         xfs_inode_t     *ip)
66 {
67         if (atomic_dec_and_test(&ip->i_iocount))
68                 wake_up(vptosync(ip));
69 }
70
71 /*
72  * Volume managers supporting multiple paths can send back ENODEV when the
73  * final path disappears.  In this case continuing to fill the page cache
74  * with dirty data which cannot be written out is evil, so prevent that.
75  */
76 void
77 vn_ioerror(
78         xfs_inode_t     *ip,
79         int             error,
80         char            *f,
81         int             l)
82 {
83         bhv_vfs_t       *vfsp = XFS_MTOVFS(ip->i_mount);
84
85         if (unlikely(error == -ENODEV))
86                 bhv_vfs_force_shutdown(vfsp, SHUTDOWN_DEVICE_REQ, f, l);
87 }
88
89 bhv_vnode_t *
90 vn_initialize(
91         struct inode    *inode)
92 {
93         bhv_vnode_t     *vp = vn_from_inode(inode);
94
95         XFS_STATS_INC(vn_active);
96         XFS_STATS_INC(vn_alloc);
97
98         spin_lock(&vnumber_lock);
99         if (!++vn_generation)   /* v_number shouldn't be zero */
100                 vn_generation++;
101         vp->v_number = vn_generation;
102         spin_unlock(&vnumber_lock);
103
104         ASSERT(VN_CACHED(vp) == 0);
105
106         return vp;
107 }
108
109 /*
110  * Revalidate the Linux inode from the vattr.
111  * Note: i_size _not_ updated; we must hold the inode
112  * semaphore when doing that - callers responsibility.
113  */
114 void
115 vn_revalidate_core(
116         bhv_vnode_t     *vp,
117         bhv_vattr_t     *vap)
118 {
119         struct inode    *inode = vn_to_inode(vp);
120
121         inode->i_mode       = vap->va_mode;
122         inode->i_nlink      = vap->va_nlink;
123         inode->i_uid        = vap->va_uid;
124         inode->i_gid        = vap->va_gid;
125         inode->i_blocks     = vap->va_nblocks;
126         inode->i_mtime      = vap->va_mtime;
127         inode->i_ctime      = vap->va_ctime;
128         if (vap->va_xflags & XFS_XFLAG_IMMUTABLE)
129                 inode->i_flags |= S_IMMUTABLE;
130         else
131                 inode->i_flags &= ~S_IMMUTABLE;
132         if (vap->va_xflags & XFS_XFLAG_APPEND)
133                 inode->i_flags |= S_APPEND;
134         else
135                 inode->i_flags &= ~S_APPEND;
136         if (vap->va_xflags & XFS_XFLAG_SYNC)
137                 inode->i_flags |= S_SYNC;
138         else
139                 inode->i_flags &= ~S_SYNC;
140         if (vap->va_xflags & XFS_XFLAG_NOATIME)
141                 inode->i_flags |= S_NOATIME;
142         else
143                 inode->i_flags &= ~S_NOATIME;
144 }
145
146 /*
147  * Revalidate the Linux inode from the vnode.
148  */
149 int
150 __vn_revalidate(
151         bhv_vnode_t     *vp,
152         bhv_vattr_t     *vattr)
153 {
154         int             error;
155
156         vn_trace_entry(xfs_vtoi(vp), __FUNCTION__, (inst_t *)__return_address);
157         vattr->va_mask = XFS_AT_STAT | XFS_AT_XFLAGS;
158         error = xfs_getattr(xfs_vtoi(vp), vattr, 0);
159         if (likely(!error)) {
160                 vn_revalidate_core(vp, vattr);
161                 xfs_iflags_clear(xfs_vtoi(vp), XFS_IMODIFIED);
162         }
163         return -error;
164 }
165
166 int
167 vn_revalidate(
168         bhv_vnode_t     *vp)
169 {
170         bhv_vattr_t     vattr;
171
172         return __vn_revalidate(vp, &vattr);
173 }
174
175 /*
176  * Add a reference to a referenced vnode.
177  */
178 bhv_vnode_t *
179 vn_hold(
180         bhv_vnode_t     *vp)
181 {
182         struct inode    *inode;
183
184         XFS_STATS_INC(vn_hold);
185
186         inode = igrab(vn_to_inode(vp));
187         ASSERT(inode);
188
189         return vp;
190 }
191
192 #ifdef  XFS_VNODE_TRACE
193
194 /*
195  * Reference count of Linux inode if present, -1 if the xfs_inode
196  * has no associated Linux inode.
197  */
198 static inline int xfs_icount(struct xfs_inode *ip)
199 {
200         bhv_vnode_t *vp = XFS_ITOV_NULL(ip);
201
202         if (vp)
203                 return vn_count(vp);
204         return -1;
205 }
206
207 #define KTRACE_ENTER(ip, vk, s, line, ra)                       \
208         ktrace_enter(   (ip)->i_trace,                          \
209 /*  0 */                (void *)(__psint_t)(vk),                \
210 /*  1 */                (void *)(s),                            \
211 /*  2 */                (void *)(__psint_t) line,               \
212 /*  3 */                (void *)(__psint_t)xfs_icount(ip),      \
213 /*  4 */                (void *)(ra),                           \
214 /*  5 */                NULL,                                   \
215 /*  6 */                (void *)(__psint_t)current_cpu(),       \
216 /*  7 */                (void *)(__psint_t)current_pid(),       \
217 /*  8 */                (void *)__return_address,               \
218 /*  9 */                NULL, NULL, NULL, NULL, NULL, NULL, NULL)
219
220 /*
221  * Vnode tracing code.
222  */
223 void
224 vn_trace_entry(xfs_inode_t *ip, const char *func, inst_t *ra)
225 {
226         KTRACE_ENTER(ip, VNODE_KTRACE_ENTRY, func, 0, ra);
227 }
228
229 void
230 vn_trace_exit(xfs_inode_t *ip, const char *func, inst_t *ra)
231 {
232         KTRACE_ENTER(ip, VNODE_KTRACE_EXIT, func, 0, ra);
233 }
234
235 void
236 vn_trace_hold(xfs_inode_t *ip, char *file, int line, inst_t *ra)
237 {
238         KTRACE_ENTER(ip, VNODE_KTRACE_HOLD, file, line, ra);
239 }
240
241 void
242 vn_trace_ref(xfs_inode_t *ip, char *file, int line, inst_t *ra)
243 {
244         KTRACE_ENTER(ip, VNODE_KTRACE_REF, file, line, ra);
245 }
246
247 void
248 vn_trace_rele(xfs_inode_t *ip, char *file, int line, inst_t *ra)
249 {
250         KTRACE_ENTER(ip, VNODE_KTRACE_RELE, file, line, ra);
251 }
252 #endif  /* XFS_VNODE_TRACE */