root/branches/Orange-Branch/src/kernel/linux-2.6/dcache.c @ 8842

Revision 8842, 9.5 KB (checked in by mtmoore, 2 years ago)

update configure checks and kernel code for 2.6.38

Line 
1/*
2 * (C) 2001 Clemson University and The University of Chicago
3 *
4 * See COPYING in top-level directory.
5 */
6
7/** \file
8 *  \ingroup pvfs2linux
9 *
10 *  Implementation of dentry (directory cache) functions.
11 */
12
13#include "pvfs2-kernel.h"
14#include "pvfs2-internal.h"
15
16static void __attribute__ ((unused)) print_dentry(struct dentry *entry, int ret);
17
18/* should return 1 if dentry can still be trusted, else 0 */
19static int pvfs2_d_revalidate_common(struct dentry* dentry)
20{
21    int ret = 0;
22    struct inode *inode;
23    struct inode *parent_inode = NULL;
24    pvfs2_kernel_op_t *new_op = NULL;
25    pvfs2_inode_t *parent = NULL;
26
27    gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: called on dentry %p.\n",
28                 __func__, dentry);
29
30    /* find inode from dentry */
31    if(!dentry || !dentry->d_inode)
32    {
33        gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: inode not valid.\n", __func__);
34        goto invalid_exit;
35    }
36
37    gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: inode valid.\n", __func__);
38    inode = dentry->d_inode;
39
40    /* find parent inode */
41    if(!dentry || !dentry->d_parent)
42    {
43        gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: parent not found.\n", __func__);
44        goto invalid_exit;
45    }
46
47    gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: parent found.\n", __func__);
48    parent_inode = dentry->d_parent->d_inode;
49
50    /* first perform a lookup to make sure that the object not only
51     * exists, but is still in the expected place in the name space
52     */
53    if (!is_root_handle(inode))
54    {
55        gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: attempting lookup.\n", __func__);
56        new_op = op_alloc(PVFS2_VFS_OP_LOOKUP);
57        if (!new_op)
58        {
59            goto invalid_exit;
60        }
61        new_op->upcall.req.lookup.sym_follow = PVFS2_LOOKUP_LINK_NO_FOLLOW;
62        parent = PVFS2_I(parent_inode);
63        if (parent && parent->refn.handle != PVFS_HANDLE_NULL &&
64            parent->refn.fs_id != PVFS_FS_ID_NULL)
65        {
66            new_op->upcall.req.lookup.parent_refn = parent->refn;
67        }
68        else
69        {
70#if defined(HAVE_IGET4_LOCKED) || defined(HAVE_IGET5_LOCKED)
71            gossip_lerr("Critical error: i_ino cannot be relied "
72                        "upon when using iget5/iget4\n");
73            op_release(new_op);
74            goto invalid_exit;
75#endif
76            new_op->upcall.req.lookup.parent_refn.handle =
77                get_handle_from_ino(parent_inode);
78            new_op->upcall.req.lookup.parent_refn.fs_id =
79                PVFS2_SB(parent_inode->i_sb)->fs_id;
80        }
81        strncpy(new_op->upcall.req.lookup.d_name,
82                dentry->d_name.name, PVFS2_NAME_LEN);
83
84        gossip_debug(GOSSIP_DCACHE_DEBUG, "%s:%s:%d interrupt flag [%d]\n",
85            __FILE__, __func__, __LINE__, get_interruptible_flag(parent_inode));
86
87        ret = service_operation(
88            new_op, "pvfs2_lookup",
89            get_interruptible_flag(parent_inode));
90
91        if((new_op->downcall.status != 0) ||
92           !match_handle(new_op->downcall.resp.lookup.refn.handle, inode))
93        {
94            gossip_debug(
95                GOSSIP_DCACHE_DEBUG,
96                "%s:%s:%d lookup failure |%s| or no match |%s|.\n",
97                __FILE__, __func__, __LINE__,
98                (new_op->downcall.status != 0) ? "true" : "false",
99                (!match_handle(new_op->downcall.resp.lookup.refn.handle, inode)) ? "true" : "false");
100            op_release(new_op);
101
102            /* Avoid calling make_bad_inode() in this situation.  On 2.4
103             * (RHEL3) kernels, it can cause bogus permission denied errors
104             * on path elements after interrupt signals.  On later 2.6
105             * kernels this causes a kernel oops rather than a permission
106             * error.
107             */
108#if 0
109            /* mark the inode as bad so that d_delete will be aggressive
110             * about dropping the dentry
111             */
112            pvfs2_make_bad_inode(inode);
113#endif
114            gossip_debug(GOSSIP_DCACHE_DEBUG, "%s:%s:%d setting revalidate_failed = 1\n", __FILE__, __func__, __LINE__);
115            /* set a flag that we can detect later in d_delete() */
116            PVFS2_I(inode)->revalidate_failed = 1;
117            d_drop(dentry);
118
119            goto invalid_exit;
120        }
121
122        op_release(new_op);
123    }
124    else
125    {
126        gossip_debug(GOSSIP_DCACHE_DEBUG,
127                     "%s: root handle, lookup skipped.\n", __func__);
128    }
129
130    /* now perform getattr */
131    gossip_debug(GOSSIP_DCACHE_DEBUG,
132                 "%s: doing getattr: inode: %p, handle: %llu)\n",
133                 __func__, inode, llu(get_handle_from_ino(inode)));
134    ret = pvfs2_inode_getattr(inode, PVFS_ATTR_SYS_ALL_NOHINT);
135    gossip_debug(GOSSIP_DCACHE_DEBUG,
136                 "%s: getattr %s (ret = %d), returning %s for dentry i_count=%d\n",
137                 __func__,
138                 (ret == 0 ? "succeeded" : "failed"),
139                 ret,
140                 (ret == 0 ? "valid" : "INVALID"),
141                 atomic_read(&inode->i_count));
142    if(ret != 0)
143    {
144        goto invalid_exit;
145    }
146
147    /* dentry is valid! */
148    return 1;
149
150invalid_exit:
151    return 0;
152}
153
154static int pvfs2_d_delete (
155#ifdef HAVE_D_DELETE_CONST
156const
157#endif /* HAVE_D_DELETE_CONST */
158struct dentry * dentry
159)
160{
161    gossip_debug(GOSSIP_DCACHE_DEBUG,
162                 "%s: called on dentry %p.\n", __func__, dentry);
163#if 0
164    if(dentry->d_inode && is_bad_inode(dentry->d_inode))
165#endif
166    if(dentry->d_inode && PVFS2_I(dentry->d_inode)->revalidate_failed == 1)
167    {
168        gossip_debug(GOSSIP_DCACHE_DEBUG,
169                     "%s: returning 1 (bad inode).\n", __func__);
170        return 1;
171    }
172    else
173    {
174        gossip_debug(GOSSIP_DCACHE_DEBUG,
175                     "%s: returning 0 (inode looks ok).\n", __func__);
176        return 0;
177    }
178}
179
180/* should return 1 if dentry can still be trusted, else 0 */
181#ifdef PVFS2_LINUX_KERNEL_2_4
182static int pvfs2_d_revalidate(
183    struct dentry *dentry,
184    int flags)
185{
186    return(pvfs2_d_revalidate_common(dentry));
187}
188
189#else
190
191/** Verify that dentry is valid.
192 */
193static int pvfs2_d_revalidate(
194    struct dentry *dentry,
195    struct nameidata *nd)
196{
197
198    if (nd && (nd->flags & LOOKUP_FOLLOW) &&
199        (!nd->flags & LOOKUP_CREATE))
200    {
201        gossip_debug(GOSSIP_DCACHE_DEBUG,
202                     "\n%s: Trusting intent; skipping getattr\n", __func__);
203        return 1;
204    }
205    return(pvfs2_d_revalidate_common(dentry));
206}
207
208#endif /* PVFS2_LINUX_KERNEL_2_4 */
209
210/*
211  to propagate an error, return a value < 0, as this causes
212  link_path_walk to pass our error up
213*/
214static int pvfs2_d_hash(
215#ifdef HAVE_THREE_PARAM_D_HASH
216    const struct dentry *parent,
217    const struct inode *inode,
218    struct qstr *hash
219#else
220    struct dentry *parent,
221    struct qstr *hash
222#endif /* HAVE_THREE_PARAM_D_HASH */
223                        )
224{
225/*     gossip_debug(GOSSIP_DCACHE_DEBUG, "pvfs2: pvfs2_d_hash called " */
226/*                 "(name: %s | len: %d | hash: %d)\n", */
227/*                 hash->name, hash->len, hash->hash); */
228    return 0;
229}
230
231#ifdef HAVE_SEVEN_PARAM_D_COMPARE
232static int pvfs2_d_compare(
233                            const struct dentry *parent,
234                            const struct inode * pinode,
235                            const struct dentry *dentry,
236                            const struct inode *inode,
237                            unsigned int len,
238                            const char *str,
239                            const struct qstr *name)
240{
241    int i = 0;
242    gossip_debug(GOSSIP_DCACHE_DEBUG, "pvfs2_d_compare: "
243                 "called on parent %p\n  (name1: %s| name2: %s)\n",
244                 parent, str, name->name);
245
246    if( len != name->len )
247        return 1;
248 
249    for( i=0; i < len; i++ )
250    {
251        if( str[i] != name->name[i] )
252            return 1;
253    }
254    return 0;
255}
256#else
257static int pvfs2_d_compare(
258    struct dentry *parent,
259    struct qstr *d_name,
260    struct qstr *name)
261{
262    gossip_debug(GOSSIP_DCACHE_DEBUG, "pvfs2_d_compare: called on parent %p\n  (name1: %s| "
263                "name2: %s)\n", parent, d_name->name, name->name);
264
265    /* if we have a match, return 0 (normally called from __d_lookup) */
266    return !((d_name->len == name->len) &&
267             (d_name->hash == name->hash) &&
268             (memcmp(d_name->name, name->name, d_name->len) == 0));
269}
270#endif /* HAVE_SEVEN_PARAM_D_COMPARE */
271
272
273/** PVFS2 implementation of VFS dentry operations */
274struct dentry_operations pvfs2_dentry_operations =
275{
276    .d_revalidate = pvfs2_d_revalidate,
277    .d_hash = pvfs2_d_hash,
278    .d_compare = pvfs2_d_compare,
279    .d_delete = pvfs2_d_delete,
280};
281
282/* print_dentry()
283 *
284 * Available for debugging purposes.  Please remove the unused attribute
285 * before invoking
286 */
287static void __attribute__ ((unused)) print_dentry(struct dentry *entry, int ret)
288{
289  unsigned int local_count = 0;
290  if(!entry)
291  {
292    printk("--- dentry %p: no entry, ret: %d\n", entry, ret);
293    return;
294  }
295
296  if(!entry->d_inode)
297  {
298    printk("--- dentry %p: no d_inode, ret: %d\n", entry, ret);
299    return;
300  }
301
302  if(!entry->d_parent)
303  {
304    printk("--- dentry %p: no d_parent, ret: %d\n", entry, ret);
305    return;
306  }
307
308#ifdef HAVE_DENTRY_D_COUNT_ATOMIC
309  local_count = atomic_read(&entry->d_count);
310#else
311  spin_lock(&entry->d_lock);
312  local_count = entry->d_count;
313  spin_unlock(&entry->d_lock);
314#endif /* HAVE_DENTRY_D_COUNT_ATOMIC */
315
316  printk("--- dentry %p: d_count: %d, name: %s, parent: %p, parent name: %s, ret: %d\n",
317        entry,
318        local_count,
319        entry->d_name.name,
320        entry->d_parent,
321        entry->d_parent->d_name.name,
322        ret);
323}
324
325/*
326 * Local variables:
327 *  c-indent-level: 4
328 *  c-basic-offset: 4
329 * End:
330 *
331 * vim: ts=8 sts=4 sw=4 expandtab
332 */
Note: See TracBrowser for help on using the browser.